Skip to content

Next.js: exception encountered in prefetchInfiniteQuery causes useSuspenseInfiniteQuery to fail #8825

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
robertzlatarski opened this issue Mar 17, 2025 · 2 comments
Labels
bug Something isn't working

Comments

@robertzlatarski
Copy link

robertzlatarski commented Mar 17, 2025

Describe the bug

I believe there is some weird behaviour when a prefetchInfiniteQuery fails in a server component and useSuspenseInfiniteQuery retries to fetch the data on the client. The exception thrown is: Uncaught TypeError: Cannot read properties of undefined (reading 'length'). I have spent some time debugging into this, it feels like after the failure on the server, the client retries to fetch the data and upon a successful response, it doesn't modify the response to be in the expected {pages: [], pageParams:[]} format, but treats it like a normal query response.

I have also noticed that query options passed are ignored (such as retry: 0).

Your minimal, reproducible example

https://codesandbox.io/p/devbox/9lyl7g

Steps to reproduce

The sandbox has an API endpoint that is setup to fail randomly. Verify that the hardcoded endpoint path is correct in pokemon.ts.

  1. Restart sandbox browser until prefetch has failed
  2. Observe an exception being thrown when a retry to /api request succeeds

Expected behavior

I expect it to work fine.

How often does this bug happen?

Always

Screenshots or Videos

Image

Platform

  • OS: MacOS
  • Chrome
  • Dependencies:

"next": "14.2.15",
"react": "18.3.1",
"react-dom": "18.3.1"

Tanstack Query adapter

None

TanStack Query version

5.62.7

TypeScript version

No response

Additional context

No response

@TkDodo
Copy link
Collaborator

TkDodo commented Mar 18, 2025

you’re right. when you’re not awaiting data on the server, we’re streaming the promise down. However, on the client, we try to pick up the promise by calling query.fetch here:

// this doesn't actually fetch - it just creates a retryer
// which will re-use the passed `initialPromise`
void query.fetch(undefined, { initialPromise })

However, for infinite queries, we need to attach the infiniteQueryBehavior, like we do in the queryClient:

options.behavior = infiniteQueryBehavior<
TQueryFnData,
TError,
TData,
TPageParam
>(options.pages)
return this.fetchQuery(options as any)

because that is what attaches the mechanism to transform data into { pages, pageParams }.

the conceptual problem I’m having now is that hydration doesn’t know about infinite / non-infinite query. There’s no information stored in the cache that knows about this.

here’s a more streamlined reproduction where the fetch always fails on the server and always succeeds on the client:

https://codesandbox.io/p/devbox/reverent-tree-forked-kwkm8p

@Ephem @juliusmarminge FYI

@TkDodo TkDodo added the bug Something isn't working label Mar 18, 2025
@Ephem
Copy link
Collaborator

Ephem commented Mar 18, 2025

Interesting! Just like with the max update depth bug I think this is another argument for not passing the promise itself down, we need to wrap it with more metadata.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants