Which project does this relate to?
Router
Describe the bug
#7753 and #7457 were closed by removing internal throw undefined sites (#7805), and #7910 tracks another one but the reason each of these was catastrophic (whole-app unmount, stackless Uncaught undefined) rather than a rendered errorComponent is still present: CatchBoundary stores the caught value and gates both reset and render on its truthiness:
static getDerivedStateFromError(error) { return { error }; }
// render():
if (error) { /* render errorComponent */ }
return this.props.children;
A thrown falsy value (undefined, null, 0, "") is caught and stored, the gate is false, the boundary re-renders the same crashing children, and React promotes it to an uncaught root error — bypassing the route's errorComponent entirely.
Any userland falsy throw reproduces it on latest; fixing the gate also makes future internal regressions of the #7753/#7910 class degrade gracefully instead of unmounting the app.
Repro (confirmed on @tanstack/react-router 1.170.29 / react 19.2.8): https://github.com/antur84/tanstack-router-falsy-error-boundary-repro.
Suggested fix: track hasError in state separately from the value so the gates don't depend on truthiness (the default ErrorComponent also needs an error?.message guard).
Complete minimal reproducer
https://github.com/antur84/tanstack-router-falsy-error-boundary-repro
Steps to Reproduce the Bug
npm install && node repro.mjs
throw new Error(...): errorComponent rendered = true, escalated to onUncaughtError = false
throw undefined : errorComponent rendered = false, escalated to onUncaughtError = true
Expected: the route errorComponent renders for any thrown value.
Actual: thrown falsy values skip it and surface as uncaught root errors.
Expected behavior
Expected: the route errorComponent renders for any thrown value.
Screenshots or Videos
No response
Platform
- Router / Start Version: 1.170.29
- OS: macOS 26.5.2
- Browser: n/a (headless repro — Node + jsdom)
- Browser Version: n/a (Node v24.14.1, jsdom 29.1.1)
- Bundler: none (plain Node ESM)
- Bundler Version: n/a
Additional context
No response
Which project does this relate to?
Router
Describe the bug
#7753 and #7457 were closed by removing internal throw undefined sites (#7805), and #7910 tracks another one but the reason each of these was catastrophic (whole-app unmount, stackless Uncaught undefined) rather than a rendered errorComponent is still present: CatchBoundary stores the caught value and gates both reset and render on its truthiness:
A thrown falsy value (undefined, null, 0, "") is caught and stored, the gate is false, the boundary re-renders the same crashing children, and React promotes it to an uncaught root error — bypassing the route's errorComponent entirely.
Any userland falsy throw reproduces it on latest; fixing the gate also makes future internal regressions of the #7753/#7910 class degrade gracefully instead of unmounting the app.
Repro (confirmed on @tanstack/react-router 1.170.29 / react 19.2.8): https://github.com/antur84/tanstack-router-falsy-error-boundary-repro.
Suggested fix: track hasError in state separately from the value so the gates don't depend on truthiness (the default ErrorComponent also needs an error?.message guard).
Complete minimal reproducer
https://github.com/antur84/tanstack-router-falsy-error-boundary-repro
Steps to Reproduce the Bug
npm install && node repro.mjsthrow new Error(...): errorComponent rendered = true, escalated to onUncaughtError = false
throw undefined : errorComponent rendered = false, escalated to onUncaughtError = true
Expected: the route errorComponent renders for any thrown value.
Actual: thrown falsy values skip it and surface as uncaught root errors.
Expected behavior
Expected: the route errorComponent renders for any thrown value.
Screenshots or Videos
No response
Platform
Additional context
No response