Skip to content

fix(react-router): Catch thrown nullish value and prevent nullish#7741

Open
joseinaqa wants to merge 1 commit into
TanStack:mainfrom
joseinaqa:fix/match-undefined-throw
Open

fix(react-router): Catch thrown nullish value and prevent nullish#7741
joseinaqa wants to merge 1 commit into
TanStack:mainfrom
joseinaqa:fix/match-undefined-throw

Conversation

@joseinaqa

@joseinaqa joseinaqa commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

loadPromise from being thrown

The issue happens in circumstances where match.status === 'redirected' but the loadPromise is nulled.
Reproduction is possible by using
https://github.com/joseinaqa/redirect-race-app and after this change does not happen anymore.

Summary by CodeRabbit

  • Bug Fixes
    • Improved error handling by normalizing “nullish thrown” cases so boundaries always receive a real Error and reliably report failures.
    • Preserved component stack details when available, improving debuggability for certain caught-error scenarios.
    • Fixed suspense/loading behavior to prevent “pending” throws from failing when match promises are undefined, using a safe never-resolving fallback.
    • Ensured client-side rethrows always throw a concrete error instead of a potentially nullish value.

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e9e4b536-cc58-4fe7-bc08-09b101de1ec3

📥 Commits

Reviewing files that changed from the base of the PR and between dbd4754 and 61fa627.

📒 Files selected for processing (2)
  • packages/react-router/src/CatchBoundary.tsx
  • packages/react-router/src/Match.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/react-router/src/Match.tsx
  • packages/react-router/src/CatchBoundary.tsx

📝 Walkthrough

Walkthrough

CatchBoundary now normalizes nullish thrown errors and updates the stored stack before calling onCatch. Match now falls back to a shared never-resolving promise when Suspense would otherwise throw nothing, and client error rethrows now always produce a concrete Error.

Changes

Error and Suspense Handling Fixes

Layer / File(s) Summary
Nullish error normalization in CatchBoundary
packages/react-router/src/CatchBoundary.tsx
Nullish thrown errors are replaced with a new Error, componentDidCatch patches the stored error's stack, and onCatch receives the normalized error.
permaPendingPromise fallback for Suspense throws
packages/react-router/src/Match.tsx
A shared permaPendingPromise is introduced and used as a fallback across server and client pending, redirect, and error throw sites to ensure a Promise is always thrown for Suspense.

Estimated code review effort: 2 (Simple) | ~12 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MatchInner
  participant getMatchPromise
  participant ReactSuspense

  MatchInner->>getMatchPromise: request match promise
  getMatchPromise-->>MatchInner: promise or undefined
  alt promise is undefined
    MatchInner->>ReactSuspense: throw permaPendingPromise
  else promise exists
    MatchInner->>ReactSuspense: throw match promise
  end
Loading

Suggested labels: package: react-router

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is directly related to the PR’s main fix: handling nullish thrown values in react-router.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/react-router/src/Match.tsx`:
- Line 523: The Match.tsx error-handling path currently throws
permaPendingPromise when match.error is nullish, which keeps the route suspended
instead of reaching the error boundary. Update the logic in Match to throw a
synthetic Error in this branch, and keep using match.error when present so
client error states render correctly rather than staying on the pending
fallback.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a7b45fc0-6aa0-4f09-8dcf-8eda61c7602c

📥 Commits

Reviewing files that changed from the base of the PR and between 208100b and dbd4754.

📒 Files selected for processing (2)
  • packages/react-router/src/CatchBoundary.tsx
  • packages/react-router/src/Match.tsx

Comment thread packages/react-router/src/Match.tsx Outdated
loadPromise from being thrown

The issue happens in circumstances where match.status === 'redirected'
but the loadPromise is nulled.
Reproduction is possible by using
https://github.com/joseinaqa/redirect-race-app and after this change
does not anymore.
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.

1 participant