Skip to content

fix: bubble errors from recovering class boundaries - #109

Open
BleedingDev wants to merge 1 commit into
TanStack:mainfrom
BleedingDev:fix/error-boundary-recovery-bubbling
Open

BleedingDev wants to merge 1 commit into
TanStack:mainfrom
BleedingDev:fix/error-boundary-recovery-bubbling

Conversation

@BleedingDev

@BleedingDev BleedingDev commented Oct 28, 2026 •

Copy link
Copy Markdown

Why the change

Let an enclosing error boundary handle errors thrown by an inner boundary's fallback without losing the recovered content's hydrated Suspense range.

Special things to note

  • This is one commit directly on 052ca013262875d4a226095b1139bd83bf206bc8, with no dependency on the SSR ID or insertion-context PRs; recovery exclusions apply only while that boundary is rendering its fallback.
  • Full suite: 185 files and 2,008 tests passed, 91 skipped; types, build verification, and all 38 size gates passed. Source/built DOM-client gzip is 25,119/25,087 B; server stays at 8,975/8,974 B. Only the hydration-disabled entry needs a measured 72/81 B allowance, reaching 22,676/22,682 B.

Change outline

Reproduce with this tree in both CSR and hydration, where Thrower throws loader failure, Rethrow throws its received error, and ErrorPage renders an interactive counter:

<Suspense fallback={null}>
  <Boundary fallback={ErrorPage}>
    <Boundary fallback={Rethrow}>
      <Thrower />
    </Boundary>
  </Boundary>
</Suspense>

packages/redact/src/dom/features/class/full.ts:103 and :126 reconcile recovery while the same class remains eligible to catch child errors. packages/redact/src/dom/reconcile.ts:768 therefore retargeted the fallback's error to that inner class instead of the outer boundary.

 render recovery
+ enter this boundary's recovery scope
  derive fallback state and reconcile
- nearest error boundary can select this recovering class again
+ nearest error boundary skips recovering ancestors
+ newly nested boundaries can still catch
+ leave recovery scope in finally

 place hydrated recovery
- collect only new host nodes, outside the retained closing marker
+ collect opening marker, children and closing marker in order
+ preserve marker ownership through client recovery and deletion
regressions
  CSR and hydration fallback rethrows
  scheduled render errors and pre-captured commit errors
  different errors thrown by fallbacks
  boundaries introduced inside a fallback
  recovery cleanup and later boundary resets
  original sibling identity, marker containment and a working counter

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Errors thrown while a boundary displays its fallback can now reach an enclosing error boundary, including during recovery and scheduled updates.
    • Fixed cases where errors during recovery could leave the original boundary in an inconsistent state or go unreported.
    • Preserved hydrated Suspense boundaries and their surrounding content during recovery, preventing boundary markers or sibling content from being lost.

Co-Authored-By: Claude Code <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Oct 28, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 3811081

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@tanstack/redact Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review 🔄 Running since 2026-10-28T19:31:39.498938Z 3811081 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 7eb6d052-d0a2-4b2a-a20d-76eb129cc970
Commits

Reviewing files that changed from the base of the PR and between 052ca01 and 3811081.

Files selected for processing: 6
  • .changeset/error-boundary-recovery.md
  • packages/redact/src/dom/features/class/full.ts
  • packages/redact/src/dom/features/suspense/full.ts
  • packages/redact/src/dom/reconcile.ts
  • scripts/size-check.mjs
  • tests/error-boundary-recovery.test.tsx

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 1 remain after this review.

Walkthrough

This change updates class error recovery so fallback errors can reach an enclosing boundary. It also preserves Suspense boundary markers during hydrated retries and includes them in host-node collection and removal. Tests cover boundary recovery across rendering, hydration, scheduled updates, and commit-time errors.

Changes: Boundary recovery

Layer / File(s) Summary
Error bubbling and validation
packages/redact/src/dom/features/class/full.ts, packages/redact/src/dom/reconcile.ts, tests/error-boundary-recovery.test.tsx, scripts/size-check.mjs
Class recovery tracks the recovering boundary, and boundary lookup skips it when selecting an ancestor. Tests cover fallback errors across rendering and update paths. The size check adds source and built-package allowances.
Suspense marker preservation and cleanup
packages/redact/src/dom/features/suspense/full.ts, packages/redact/src/dom/reconcile.ts, .changeset/error-boundary-recovery.md
Hydration retries retain the Suspense start and end markers. Host-node collection and removal include those markers. The changeset records the recovery and marker changes.

Priority: Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Possibly related PRs

  • TanStack/redact#95: Changes Suspense hydration retries and preservation of server DOM ranges, related to marker handling here.
  • TanStack/redact#103: Changes Suspense marker ranges and fallback-range removal, related to marker cleanup here.
  • TanStack/redact#76: Covers class rendering and Suspense boundary-error paths related to the recovery logic here.

Suggested reviewers: tannerlinsley

Merge Risk: Minimal · up to 38110

The reviewed recovery and hydration changes have no identified merge-blocking issue; merge after normal checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documenta… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: bubbling errors from recovering class boundaries to enclosing boundaries.
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.
Full details: Docstring Coverage

Explanation

Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 6 functions across 5 files. (1 skipped: 1 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

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