Hydration error thrown during a client-side navigation while a nested route is still hydrating
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 15.1k
- Forks
- 1.9k
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 143
Description
Which project does this relate to?
Router
Describe the bug
We have been noticing hydration errors in a real world application, both in development and production. However, the issue is much easier to reproduce in development.
It's occurring when a client-side navigation is triggered by a parent route that has already hydrated, while a nested route is still hydrating.
The reproduction repo is very minimal, and renders 10,000 span elements in the page/$name route. To reproduce we navigate from /page/origin to /page/destination. The idea is to click the link (which is in __root) quickly after hydration, while the nested route is still hydrating, as in this screen recording:
https://github.com/user-attachments/assets/d9bb054b-591c-476b-a1f4-667ecf5ea329
The hydrated flag comes from the useHydrated() hook. As you can see from the logs:
__root__ hydrated=true
page/origin hydrated=false
page/destination hydrated=false
page/destination hydrated=true
The nested route flipped from page/origin hydrated=false to page/destination hydrated=false, and hydrated with the destination content, causing the hydration mismatch.
The page/$name route also renders a <title>, which is causing duplicate <title> elements after the client-side navigation.
If this proves difficult to reproduce manually, I have included a playwright script in repro.mjs, which you can run through npm run repro (this relies on the dev server being up at port 7112). The script runs the same scenario as above, and should output:
{
"routeName": "destination",
"titles": [
"destination",
"origin"
],
"hydrationErrors": 1
}
This might be related to #8233, but it does not appear the PR there (#8292) addresses this specific scenario.
Complete minimal reproducer
https://github.com/ali-idrizi/tanstack-router-navigation-during-hydration-repro
Steps to Reproduce the Bug
- Clone the repo and run
npm install npm run dev
Then either:
- Open
localhost:7112/page/originin your browser - Click the link to navigate to
page/destination. This requires timing the click quickly after "(hydrated)" appears next to the link - Notice the hydration error in the console
Or:
-
In another terminal, run the automated reproduction:
npx playwright install chromium npm run repro -
Observe the result:
{ "routeName": "destination", "titles": [ "destination", "origin" ], "hydrationErrors": 1 }
Expected behavior
No hydration error should occur.
Screenshots or Videos
No response
Platform
- Router:
1.170.33 - Start:
1.168.50 - OS: Linux
- Browser: Chrome
- Browser Version:
153.0 - Bundler: Vite
- Bundler Version:
8.2.2
Additional context
No response
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the minimal reproducer and run npm install, npm run dev, then npm run repro from repro.mjs. Trace the client-side navigation and nested hydration path for page/$name; done means the reproduction reports destination with no hydration errors and only the expected title.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- playwright, typescript, vite
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100