feat: support lazy error component on beforeLoad failures
Current behaviour: if you .lazy() an error component on a beforeLoad, then the error component won't be use and the default one will be instead
Reproduction of current error: https://stackblitz.com/edit/tanstack-router-wiqzauc7?file=src%2Fmain.tsx
Open questions:
I have the following test failing (most likely due to the loading of the lazy component):
FAIL @tanstack/react-router tests/store-updates-during-navigation.test.tsx > Store doesn't update *too many* times during navigation > not found in beforeLoad
AssertionError: expected 8 to be 7 // Object.is equality
- Expected
+ Received
- 7
+ 8
Is that ok to bump to 8 ?
Summary by CodeRabbit
Release Notes
- Bug Fixes
- Enhanced error handling flow to ensure route resources are properly loaded before error processing
- Improved support for lazy-loaded error components across router implementations
Walkthrough
Multiple test files are restructured to support lazy error component testing through a new parameterization flag. The error handling in load-matches.ts is modified to ensure route chunks load before error processing. A formatting line is added to useNavigate.tsx.
Changes
| Cohort / File(s) | Change Summary |
|---|---|
Formatting packages/react-router/src/useNavigate.tsx |
Added blank line after import type block. |
Lazy Error Component Tests packages/react-router/tests/errorComponent.test.tsx, packages/solid-router/tests/errorComponent.test.tsx |
Introduced isUsingLazyError parameterization wrapper around existing error component tests; routes now conditionally use lazy() with createLazyRoute to supply error components when isUsingLazyError = true; adjusted timeouts for lazy-loading delays. |
Error Handling Flow packages/router-core/src/load-matches.ts |
Modified executeBeforeLoad error handling to await loadRouteChunk(route) before invoking handleSerialError, ensuring route chunks load prior to error processing. |
Sequence Diagram(s)
sequenceDiagram
participant App
participant executeBeforeLoad
participant Chunk as loadRouteChunk
participant Error as handleSerialError
App->>executeBeforeLoad: Begin before load
executeBeforeLoad->>executeBeforeLoad: Execute route logic
rect rgb(200, 220, 255)
Note over executeBeforeLoad,Error: On Error (New Flow)
executeBeforeLoad->>Chunk: Await load route chunk
Chunk-->>executeBeforeLoad: Chunk loaded
executeBeforeLoad->>Error: Handle error with chunk ready
end
Error-->>App: Error handled
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~20 minutes
The changes mix formatting updates, substantial test restructuring with new lazy-loading patterns across two test files, and focused error-handling logic modifications. The heterogeneity of changes and test complexity warrant moderate review effort despite homogeneous patterns within test parameterizations.
Possibly related PRs
- #4961: Modifies
executeBeforeLoadand error handling inload-matches.tsto ensure route chunks load before serial error processing—directly related to the error handling changes. - #4971: Also modifies
executeBeforeLoadand error-handling flow inload-matches.tswith similar chunk-loading-before-error-handling logic. - #4993: Refactors
beforeLoadexecution and skip logic, relating to the overall control-flow adjustments inexecuteBeforeLoad.
Suggested reviewers
- Sheraff
- nlynzaad
- schiller-manuel
Poem
🐰 Lazy chunks now load before errors appear,
Tests wrap in parameters, the path becomes clear!
Error handling flows with a promise in hand,
While React and Solid dance across the land. ✨
Pre-merge checks and finishing touches
❌ Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Docstring Coverage | ⚠️ Warning | Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. | You can run @coderabbitai generate docstrings to improve docstring coverage. |
✅ Passed checks (2 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title Check | ✅ Passed | The PR title "feat: support lazy error component on beforeLoad failures" directly aligns with the main objective stated in the pull request, which is to add support for using a lazily loaded error component when a route's beforeLoad handler fails. The title accurately summarizes the primary feature being implemented across the changeset, including the key behavioral change in load-matches.ts and the corresponding test updates in both react-router and solid-router packages. The title is specific, clear, and avoids vague terminology, making it immediately understandable to someone reviewing the commit history. |
✨ Finishing touches
- [ ] 📝 Generate docstrings
🧪 Generate unit tests (beta)
- [ ] Create PR with unit tests
- [ ] Post copyable unit tests in a comment
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.
Comment @coderabbitai help to get the list of available commands and usage tips.
🤖 Nx Cloud AI Fix Eligible
An automatically generated fix could have helped fix failing tasks for this run, but Self-healing CI is disabled for this workspace. Visit workspace settings to enable it and get automatic fixes in future runs.
To disable these notifications, a workspace admin can disable them in workspace settings.
View your CI Pipeline Execution ↗ for commit 52e8c8b5afd4a2d3d0b9954450b0ce8bc24ab822
| Command | Status | Duration | Result |
|---|---|---|---|
nx affected --targets=test:eslint,test:unit,tes... |
❌ Failed | 7m 33s | View ↗ |
nx run-many --target=build --exclude=examples/*... |
✅ Succeeded | 1m 24s | View ↗ |
☁️ Nx Cloud last updated this comment at 2025-11-19 23:11:23 UTC
More templates
- tanstack-router-react-example-authenticated-routes
- tanstack-router-react-example-authenticated-routes-firebase
- tanstack-router-react-example-basic
- tanstack-router-react-example-basic-default-search-params
- tanstack-router-react-example-basic-devtools-panel
- tanstack-router-react-example-basic-file-based
- tanstack-router-react-example-basic-non-nested-devtools
- tanstack-router-react-example-react-query
- tanstack-router-react-example-basic-react-query-file-based
- tanstack-router-react-example-basic-ssr-file-based
- tanstack-router-react-example-basic-ssr-streaming-file-based
- tanstack-router-react-example-basic-virtual-file-based
- tanstack-router-react-example-basic-virtual-inside-file-based
- tanstack-router-react-example-deferred-data
- tanstack-router-i18n-paraglide
- tanstack-router-react-example-kitchen-sink
- tanstack-router-react-example-kitchen-sink-file-based
- tanstack-router-react-example-kitchen-sink-react-query
- tanstack-router-react-example-kitchen-sink-react-query-file-based
- tanstack-router-react-example-large-file-based
- tanstack-router-react-example-location-masking
- tanstack-router-react-example-navigation-blocking
- tanstack-router-react-example-quickstart
- tanstack-router-react-example-quickstart-esbuild-file-based
- tanstack-router-react-example-quickstart-file-based
- tanstack-router-react-example-quickstart-rspack-file-based
- tanstack-router-react-example-quickstart-webpack-file-based
- router-monorepo-react-query
- router-mono-simple
- router-mono-simple-lazy
- tanstack-router-react-example-scroll-restoration
- tanstack-search-validator-adapters
- tanstack-start-example-bare
- tanstack-start-example-basic
- tanstack-start-example-basic-auth
- tanstack-start-example-basic-cloudflare
- tanstack-start-example-basic-react-query
- tanstack-start-example-basic-static
- tanstack-start-bun-hosting
- tanstack-start-example-clerk-basic
- tanstack-start-example-convex-trellaux
- tanstack-start-example-counter
- tanstack-start-i18n-paraglide
- tanstack-start-example-large
- tanstack-start-example-material-ui
- tanstack-start-streaming-data-from-server-functions
- tanstack-start-example-supabase-basic
- tanstack-start-tailwind-v4
- tanstack-start-example-trellaux
- tanstack-start-example-workos
- tanstack-router-react-example-view-transitions
- tanstack-router-react-example-with-framer-motion
- tanstack-router-react-example-with-trpc
- tanstack-router-react-example-with-trpc-react-query
- tanstack-router-solid-example-authenticated-routes
- tanstack-router-solid-example-authenticated-routes-firebase
- tanstack-router-solid-example-basic
- tanstack-router-solid-example-basic-default-search-params
- tanstack-router-solid-example-basic-devtools-panel
- tanstack-router-solid-example-basic-file-based
- tanstack-router-solid-example-basic-non-nested-devtools
- tanstack-router-solid-example-basic-solid-query
- tanstack-router-solid-example-basic-solid-query-file-based
- tanstack-router-solid-example-basic-ssr-file-based
- tanstack-router-solid-example-basic-ssr-streaming-file-based
- tanstack-router-solid-example-basic-virtual-file-based
- tanstack-router-solid-example-basic-virtual-inside-file-based
- tanstack-router-solid-example-deferred-data
- tanstack-router-solid-i18n-paraglide
- tanstack-router-solid-example-kitchen-sink
- tanstack-router-solid-example-kitchen-sink-file-based
- tanstack-router-solid-example-kitchen-sink-solid-query
- tanstack-router-solid-example-kitchen-sink-solid-query-file-based
- tanstack-router-solid-example-large-file-based
- tanstack-router-solid-example-location-masking
- tanstack-router-solid-example-navigation-blocking
- tanstack-router-solid-example-quickstart
- tanstack-router-solid-example-quickstart-esbuild-file-based
- tanstack-router-solid-example-quickstart-file-based
- tanstack-router-solid-example-quickstart-rspack-file-based
- tanstack-router-solid-example-quickstart-webpack-file-based
- router-solid-mono-simple
- router-solid-mono-simple-lazy
- router-solid-monorepo-solid-query
- tanstack-router-solid-example-scroll-restoration
- tanstack-solid-router-search-validator-adapters
- tanstack-solid-start-example-basic
- tanstack-solid-start-example-basic-auth
- tanstack-solid-start-example-basic-cloudflare
- tanstack-solid-start-example-basic-netlify
- tanstack-solid-start-example-basic-nitro
- tanstack-start-example-basic-solid-query
- tanstack-solid-start-example-basic-static
- tanstack-solid-start-bun-hosting
- tanstack-solid-start-example-convex-better-auth
- tanstack-solid-start-example-counter
- tanstack-solid-start-i18n-paraglide
- tanstack-solid-start-example-large
- tanstack-solid-start-streaming-data-from-server-functions
- tanstack-solid-start-example-supabase-basic
- tanstack-solid-start-tailwind-v4
- tanstack-router-solid-example-view-transitions
- tanstack-router-solid-example-with-framer-motion
- tanstack-router-solid-example-with-trpc
@tanstack/arktype-adapter
npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@5568
@tanstack/directive-functions-plugin
npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@5568
@tanstack/eslint-plugin-router
npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@5568
@tanstack/history
npm i https://pkg.pr.new/TanStack/router/@tanstack/history@5568
@tanstack/nitro-v2-vite-plugin
npm i https://pkg.pr.new/TanStack/router/@tanstack/nitro-v2-vite-plugin@5568
@tanstack/react-router
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@5568
@tanstack/react-router-devtools
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@5568
@tanstack/react-router-ssr-query
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-ssr-query@5568
@tanstack/react-start
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@5568
@tanstack/react-start-client
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@5568
@tanstack/react-start-server
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@5568
@tanstack/router-cli
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@5568
@tanstack/router-core
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@5568
@tanstack/router-devtools
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@5568
@tanstack/router-devtools-core
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@5568
@tanstack/router-generator
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@5568
@tanstack/router-plugin
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@5568
@tanstack/router-ssr-query-core
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-ssr-query-core@5568
@tanstack/router-utils
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@5568
@tanstack/router-vite-plugin
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@5568
@tanstack/server-functions-plugin
npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@5568
@tanstack/solid-router
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@5568
@tanstack/solid-router-devtools
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@5568
@tanstack/solid-router-ssr-query
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-ssr-query@5568
@tanstack/solid-start
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@5568
@tanstack/solid-start-client
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@5568
@tanstack/solid-start-server
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@5568
@tanstack/start-client-core
npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@5568
@tanstack/start-plugin-core
npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@5568
@tanstack/start-server-core
npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@5568
@tanstack/start-static-server-functions
npm i https://pkg.pr.new/TanStack/router/@tanstack/start-static-server-functions@5568
@tanstack/start-storage-context
npm i https://pkg.pr.new/TanStack/router/@tanstack/start-storage-context@5568
@tanstack/valibot-adapter
npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@5568
@tanstack/virtual-file-routes
npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@5568
@tanstack/zod-adapter
npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@5568
commit: 52e8c8b
Is that ok to bump to 8 ?
Yes that seems good
Yes that seems good
Great, thanks! Then I guess the pr is good to go from my point of view
Then I guess the pr is good to go from my point of view
I do think we should at least make sure not to load the components if it's throwing a redirect.
I do think we should at least make sure not to load the components if it's throwing a redirect.
Done