TanStack / TanStack/router

Hydration error thrown during a client-side navigation while a nested route is still hydrating

Open
#8,306 0 comments 0 reactions 0 assignees View on GitHub

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
  1. Clone the repo and run npm install
  2. npm run dev

Then either:

  1. Open localhost:7112/page/origin in your browser
  2. Click the link to navigate to page/destination. This requires timing the click quickly after "(hydrated)" appears next to the link
  3. Notice the hydration error in the console

Or:

  1. In another terminal, run the automated reproduction:

    npx playwright install chromium
    npm run repro
    
  2. 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.