Skip to content

fix(solid-router): resolve defaultNotFoundComponent at render time to avoid hydration desync#7734

Merged
birkskyum merged 3 commits into
TanStack:solid-router-v2-prefrom
brenelz:fix/solid-router-default-not-found-hydration
Jul 2, 2026
Merged

fix(solid-router): resolve defaultNotFoundComponent at render time to avoid hydration desync#7734
birkskyum merged 3 commits into
TanStack:solid-router-v2-prefrom
brenelz:fix/solid-router-default-not-found-hydration

Conversation

@brenelz

@brenelz brenelz commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Problem

defaultNotFoundComponent used to be applied by lazily mutating the boundary route's options.notFoundComponent when a notFound() was handled (in load-matches). Route objects are module singletons shared across server requests, so once the server handled a single 404 for a route, every subsequent SSR of a valid URL on that route wrapped the match in a CatchNotFound boundary.

A freshly-hydrating client never runs that mutation, so it doesn't render the boundary — every _hk under the match shifts, hydration leaves the subtree unclaimed, and the result is visible but inert SSR DOM (no event handlers bound).

Fix

Resolve defaultNotFoundComponent at render time in Match.tsx so the presence of the CatchNotFound boundary — and therefore Solid's hydration keys — is deterministic on both server and client, regardless of whether the server previously served a 404.

Tests

Added an e2e regression test in e2e/solid-start/query-integration:

  • After the server handles a 404 for a route, a direct visit to a valid URL on the same route hydrates correctly: no unclaimed-DOM hydration warnings and the page is interactive (click probe).
  • Reloading the 404 URL itself hydrates the default not-found component without hydration warnings.

… avoid hydration desync

Previously defaultNotFoundComponent was applied by lazily mutating the
boundary route's options.notFoundComponent when a notFound was handled.
Route objects are module singletons shared across server requests, so
once the server handled any 404, later SSRs of valid URLs wrapped the
match in a CatchNotFound boundary the freshly-hydrating client doesn't
render, shifting hydration keys and leaving the subtree unclaimed
(visible but inert DOM).

Resolve defaultNotFoundComponent at render time in Match.tsx so the
boundary structure is deterministic on both server and client, and add
an e2e regression test.
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: acd98f22-d541-42b9-bd73-238981ada542

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@nx-cloud

nx-cloud Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

View your CI Pipeline Execution ↗ for commit 85f092a

Command Status Duration Result
nx affected --targets=test:eslint,test:unit,tes... ✅ Succeeded 4m 22s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 28s View ↗

☁️ Nx Cloud last updated this comment at 2026-07-02 21:02:19 UTC

@pkg-pr-new

pkg-pr-new Bot commented Jul 2, 2026

Copy link
Copy Markdown
More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/@tanstack/arktype-adapter@7734

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/@tanstack/eslint-plugin-router@7734

@tanstack/eslint-plugin-start

npm i https://pkg.pr.new/@tanstack/eslint-plugin-start@7734

@tanstack/history

npm i https://pkg.pr.new/@tanstack/history@7734

@tanstack/nitro-v2-vite-plugin

npm i https://pkg.pr.new/@tanstack/nitro-v2-vite-plugin@7734

@tanstack/react-router

npm i https://pkg.pr.new/@tanstack/react-router@7734

@tanstack/react-router-devtools

npm i https://pkg.pr.new/@tanstack/react-router-devtools@7734

@tanstack/react-router-ssr-query

npm i https://pkg.pr.new/@tanstack/react-router-ssr-query@7734

@tanstack/react-start

npm i https://pkg.pr.new/@tanstack/react-start@7734

@tanstack/react-start-client

npm i https://pkg.pr.new/@tanstack/react-start-client@7734

@tanstack/react-start-rsc

npm i https://pkg.pr.new/@tanstack/react-start-rsc@7734

@tanstack/react-start-server

npm i https://pkg.pr.new/@tanstack/react-start-server@7734

@tanstack/router-cli

npm i https://pkg.pr.new/@tanstack/router-cli@7734

@tanstack/router-core

npm i https://pkg.pr.new/@tanstack/router-core@7734

@tanstack/router-devtools

npm i https://pkg.pr.new/@tanstack/router-devtools@7734

@tanstack/router-devtools-core

npm i https://pkg.pr.new/@tanstack/router-devtools-core@7734

@tanstack/router-generator

npm i https://pkg.pr.new/@tanstack/router-generator@7734

@tanstack/router-plugin

npm i https://pkg.pr.new/@tanstack/router-plugin@7734

@tanstack/router-ssr-query-core

npm i https://pkg.pr.new/@tanstack/router-ssr-query-core@7734

@tanstack/router-utils

npm i https://pkg.pr.new/@tanstack/router-utils@7734

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/@tanstack/router-vite-plugin@7734

@tanstack/solid-router

npm i https://pkg.pr.new/@tanstack/solid-router@7734

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/@tanstack/solid-router-devtools@7734

@tanstack/solid-router-ssr-query

npm i https://pkg.pr.new/@tanstack/solid-router-ssr-query@7734

@tanstack/solid-start

npm i https://pkg.pr.new/@tanstack/solid-start@7734

@tanstack/solid-start-client

npm i https://pkg.pr.new/@tanstack/solid-start-client@7734

@tanstack/solid-start-server

npm i https://pkg.pr.new/@tanstack/solid-start-server@7734

@tanstack/start-client-core

npm i https://pkg.pr.new/@tanstack/start-client-core@7734

@tanstack/start-fn-stubs

npm i https://pkg.pr.new/@tanstack/start-fn-stubs@7734

@tanstack/start-plugin-core

npm i https://pkg.pr.new/@tanstack/start-plugin-core@7734

@tanstack/start-server-core

npm i https://pkg.pr.new/@tanstack/start-server-core@7734

@tanstack/start-static-server-functions

npm i https://pkg.pr.new/@tanstack/start-static-server-functions@7734

@tanstack/start-storage-context

npm i https://pkg.pr.new/@tanstack/start-storage-context@7734

@tanstack/valibot-adapter

npm i https://pkg.pr.new/@tanstack/valibot-adapter@7734

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/@tanstack/virtual-file-routes@7734

@tanstack/vue-router

npm i https://pkg.pr.new/@tanstack/vue-router@7734

@tanstack/vue-router-devtools

npm i https://pkg.pr.new/@tanstack/vue-router-devtools@7734

@tanstack/vue-router-ssr-query

npm i https://pkg.pr.new/@tanstack/vue-router-ssr-query@7734

@tanstack/vue-start

npm i https://pkg.pr.new/@tanstack/vue-start@7734

@tanstack/vue-start-client

npm i https://pkg.pr.new/@tanstack/vue-start-client@7734

@tanstack/vue-start-server

npm i https://pkg.pr.new/@tanstack/vue-start-server@7734

@tanstack/zod-adapter

npm i https://pkg.pr.new/@tanstack/zod-adapter@7734

commit: 85f092a

@codspeed-hq

codspeed-hq Bot commented Jul 2, 2026

Copy link
Copy Markdown

Merging this PR will improve performance by 84.75%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 4 improved benchmarks
✅ 2 untouched benchmarks
🆕 90 new benchmarks

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation ssr request loop (react) 330.5 ms 81.2 ms ×4.1
Simulation client-side navigation loop (solid) 72.6 ms 42.7 ms +70.17%
Simulation ssr request loop (vue) 420.3 ms 286.8 ms +46.54%
Simulation ssr request loop (solid) 174.6 ms 152.2 ms +14.74%
🆕 Simulation ssr not-found (vue) N/A 168.8 ms N/A
🆕 Simulation ssr redirect (vue) N/A 68.4 ms N/A
🆕 Simulation ssr head (vue) N/A 325.1 ms N/A
🆕 Simulation ssr loaders (vue) N/A 136.6 ms N/A
🆕 Simulation ssr selective (vue) N/A 139.8 ms N/A
🆕 Simulation ssr server-fn GET (vue) N/A 74.5 ms N/A
🆕 Simulation ssr server-fn POST (vue) N/A 71.4 ms N/A
🆕 Simulation ssr server-route middleware (vue) N/A 63.3 ms N/A
🆕 Simulation ssr server-route (vue) N/A 60.7 ms N/A
🆕 Simulation ssr streaming deferred (vue) N/A 104.9 ms N/A
🆕 Simulation ssr assets inline-css cdn (vue) N/A 187.6 ms N/A
🆕 Simulation ssr assets linked-css control (vue) N/A 214.1 ms N/A
🆕 Simulation ssr before-load chain (vue) N/A 184 ms N/A
🆕 Simulation ssr control-flow error 500 (vue) N/A 198.2 ms N/A
🆕 Simulation ssr control-flow route headers (vue) N/A 212.5 ms N/A
🆕 Simulation ssr control-flow unmatched 404 (vue) N/A 189.8 ms N/A
... ... ... ... ... ...

ℹ️ Only the first 20 benchmarks are displayed. Go to the app to view all benchmarks.

Tip

Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.


Comparing brenelz:fix/solid-router-default-not-found-hydration (85f092a) with solid-router-v2-pre (67a9040)1

Open in CodSpeed

Footnotes

  1. No successful run was found on solid-router-v2-pre (ec08c16) during the generation of this report, so 67a9040 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@birkskyum birkskyum merged commit f9b0e57 into TanStack:solid-router-v2-pre Jul 2, 2026
18 of 20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants