Bug: Can't preload a page with pagination

This is my frontend code:
export default async function HomePage() {
const preloadedPosts = await preloadQuery(api.posts.getNewestPosts, {
paginationOpts: {
numItems: 30,
cursor: "1",
},
});

return (
<main>
<PostOverview preloadedPosts={preloadedPosts} />
</main>
);
}
export default async function HomePage() {
const preloadedPosts = await preloadQuery(api.posts.getNewestPosts, {
paginationOpts: {
numItems: 30,
cursor: "1",
},
});

return (
<main>
<PostOverview preloadedPosts={preloadedPosts} />
</main>
);
}
And this my backend code:
export const getNewestPosts = query({
args: { paginationOpts: paginationOptsValidator },
handler: (ctx, args) => {
return (
ctx
.table("posts")
.order("desc")
.paginate(args.paginationOpts)
);
},
});
export const getNewestPosts = query({
args: { paginationOpts: paginationOptsValidator },
handler: (ctx, args) => {
return (
ctx
.table("posts")
.order("desc")
.paginate(args.paginationOpts)
);
},
});
And I always get this error:
[ Server ] Error: [Request ID: ff4dc13bc227ab5a] Server Error
Uncaught Error: Failed to parse cursor
at async PromisePaginationResultOrNullImpl.retrieve (../../node_modules/.pnpm/convex-ents@0.13.0_convex@1.17.0_react-dom@18.3.1_react@18.3.1__react@18.3.1_/node_modules/convex-ents/src/functions.ts:394:6)
at async docs [as docs] (../../node_modules/.pnpm/convex-ents@0.13.0_convex@1.17.0_react-dom@18.3.1_react@18.3.1__react@18.3.1_/node_modules/convex-ents/src/functions.ts:627:19)
[ Server ] Error: [Request ID: ff4dc13bc227ab5a] Server Error
Uncaught Error: Failed to parse cursor
at async PromisePaginationResultOrNullImpl.retrieve (../../node_modules/.pnpm/convex-ents@0.13.0_convex@1.17.0_react-dom@18.3.1_react@18.3.1__react@18.3.1_/node_modules/convex-ents/src/functions.ts:394:6)
at async docs [as docs] (../../node_modules/.pnpm/convex-ents@0.13.0_convex@1.17.0_react-dom@18.3.1_react@18.3.1__react@18.3.1_/node_modules/convex-ents/src/functions.ts:627:19)
No description
9 Replies
FleetAdmiralJakob πŸ—• πŸ—— πŸ—™
Somehow the values land in Convex but they are not used correctly: Thats a console.log(args);
[CONVEX Q(posts:getNewestPosts)] [LOG] {
paginationOpts: {
cursor: '1',
numItems: 30
}
}
[CONVEX Q(posts:getNewestPosts)] [LOG] {
paginationOpts: {
cursor: '1',
numItems: 30
}
}
deen
deenβ€’5w ago
You can't preload a paginated query. If you look inside the convex client, you'll see that the cursors are these giant strings which describe the chunks of documents to get. I would safely assume this also includes a session id, which can only be used by that session. When you preload data, that request is sent by the convex client on the server, (eg.) vercel's servers. When you "hydrate", now the client is trying to use that same cursor with session id in the pagination request - ie. on your computer. Uncaught Error: Failed to parse cursor is likely the result of this. But it's OK! Just make a regular, non-paginated query that requests the same chunk of data on the server - and server render that first. When the client finally loads the paginated results, you can swap out the data. It will (probably) be exactly the same.
FleetAdmiralJakob πŸ—• πŸ—— πŸ—™
hmm interesting but isnt that a lil bit inconvienient? seems a little bit odd to create a second query just to preload the data. I would need to keep both queries in sync in order for them to fetch the same data Additionally I would still need to have the pagination functionality in the preload query, so I need a way to synchronize even with the underlying pagination code right?
deen
deenβ€’5w ago
More than a little inconvenient - that's why I don't bother doing it anymore. But it's not so odd... paginated queries have internal state that changes over time - triggered by loadMore(). RSCs don't support this directly. They fire their payload and are no longer involved with whatever the client wants to do with the data. Note the different shape of preloadQuery - it looks like a useQuery but it's not a hook, it's a one off. Like a websocket fetch. But yeah when you look at it with how we're expected to use Next.js, it feels really weird. And they could support it more directly, if they wanted to. But SSR really isn't the convex's teams vibe - especially not lately! So, these queries to be seperate, if you're going to try what seems like the obvious route. We can't synchronize the queries. So you need to ditch the one from the server somehow, otherwise you're maintaining a double query for the same data.
FleetAdmiralJakob πŸ—• πŸ—— πŸ—™
Ok, very sad 😩
deen
deenβ€’5w ago
Server side rendering a page that uses a paginated query is possible, convex just doesn't give you the sugar. I haven't tred this, but it might be easier to conceptualize and implement by using the basic convex client for the one off request. I've been thinking about making a library/component to make this super simple, but I just decided it wasn't worth my time at this stage. Try a nice skeleton loader instead, they work wonders πŸ˜‰
jamwt
jamwtβ€’4w ago
tanstack-style SSR is our vibe πŸ˜›
deen
deenβ€’4w ago
I'm trying to be diplomatic 😁 Might be worth adding a tiny note to the docs though, I'm sure countless others have run into this and suffered in silence
edproton
edprotonβ€’5d ago
If you create something please share with us :convexspin: I found it @deen many thanks https://discord.com/channels/1019350475847499849/1240700854319972523/1240752435018858546 Hello @jamwt , I’m a big fan of TanStack tools, and Tanner’s vision (even the React community reveres himβ€”who is this wizard, haha) is truly mind-blowing! I’m curious, what led you to prefer TanStack Start? By the way, I discovered Convex through TanStack Start’s sponsorshipβ€”such a great connection there!