router icon indicating copy to clipboard operation
router copied to clipboard

Tanstack Router (with Tanstack Query) throws CancelledError when navigating between pages

Open cirex-web opened this issue 6 months ago • 0 comments

Which project does this relate to?

Router

Describe the bug

By configuring the Router as below and using a useQuery hook on page 1 and a fetchQuery call in beforeLoad on page 2 (same key), navigating from page 1 to page 2 crashes with CancelledError.

  • defaultPreload: “intent”
  • defaultPendingComponent component is set (can make defaultPendingMs 0 so the error is more instant. but we can leave as default)
  • added if (preload) return; in page 2 beforeLoad to “block” preloading (this isn't necessary to create the issue but it helps with the demo)

Your Example Website or App

https://codesandbox.io/p/github/cirex-web/tanstack-router-cancellederror-demo/main

Steps to Reproduce the Bug or Issue

  1. Load home page (Observer gets mounted (by useQuery or useSuspenseQuery) with queryKey “key” on Page 1)
  2. Wait until “key” goes stale
  3. Navigate to Page 2, whose beforeLoad function calls queryClient.fetchQuery using the same queryKey “key”. queryFn accepts the abort signal argument.
  4. If queryFn is slow, a CancelledError is thrown by the fetchQuery call with the stacktrace

Image (seems like this is caused by the page 1 observer unmounting)

If we move the beforeLoad code into loader, we get the same error. In fact, we don’t even need a pending component defined to get the error!

Expected behavior

The fetch in either beforeLoad or loader should probably just work, irrespective of observers unmounting on the previous page.

Screenshots or Videos

https://github.com/user-attachments/assets/bf0d73b8-6a0a-430e-900d-eb434ec8a778

Platform

  • OS: macOS
  • Browser: Chrome
  • Router Version: 1.121.24
  • Query Version: 5.80.7

Additional context

From a bit of investigation, all of the following changes will individually fix this problem:

  • set defaultPreload to false
  • replace fetchQuery in beforeLoader with ensureQueryData
  • Remove the if (preload) return; check and hope that the user clicks on the button before the queryclient data goes stale again
    • unclear why this fixes the problem
  • Remove defaultPendingComponent
  • Remove the signal argument in queryFn. (Possible, but some tanstack query wrappers like openapi-react-query accept signal by default in its queryFn https://github.com/openapi-ts/openapi-typescript/blob/99c346e06bb41511338d2a8c3752748e5d52a742/packages/openapi-react-query/src/index.ts#L230)

The last option feels the most “correct,” but are there any other fixes?

Also, is the error expected behavior? I don’t know much about what happens under-the-hood for Tanstack Router - why does it only happen when there’s a loading component defined and preloading is enabled?

cirex-web avatar Jun 19 '25 22:06 cirex-web