Skip to content

fix: retry error boundary queries on remount#10822

Closed
EduardF1 wants to merge 2 commits into
TanStack:mainfrom
EduardF1:fix-error-boundary-retry-on-mount
Closed

fix: retry error boundary queries on remount#10822
EduardF1 wants to merge 2 commits into
TanStack:mainfrom
EduardF1:fix-error-boundary-retry-on-mount

Conversation

@EduardF1

@EduardF1 EduardF1 commented May 28, 2026

Copy link
Copy Markdown

Fixes #2712

Summary

  • Allow non-suspense error-boundary queries to retry on a fresh mount after the failed observer has been unmounted.
  • Keep retry suppression while the failed observer is still mounted, and preserve the existing suspense error-boundary behavior.
  • Update React Query error-boundary tests to cover retry-on-remount behavior.

Validation

  • ..\..\node_modules\.bin\vitest.CMD QueryResetErrorBoundary.test.tsx --run from packages\react-query (14 tests passed)

Summary by CodeRabbit

  • Bug Fixes

    • Error boundary behavior refined so queries can retry on remount while respecting reset state.
    • Retry prevention now considers suspense mode and whether a query has active observers.
  • Tests

    • Updated tests to assert retry-on-remount behavior and to track query execution counts.

Review Change Stack

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 70c16444-09b2-41d3-852c-01212b486c49

📥 Commits

Reviewing files that changed from the base of the PR and between b1e18fd and 9bb9aa6.

📒 Files selected for processing (1)
  • packages/react-query/src/__tests__/QueryResetErrorBoundary.test.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/react-query/src/tests/QueryResetErrorBoundary.test.tsx

📝 Walkthrough

Walkthrough

The PR refines React Query's error boundary retry logic by expanding the retry-prevention condition in ensurePreventErrorBoundaryRetry to check whether the query is in suspense mode or has active observers. Tests are updated to verify that queries now retry on remount even when the error boundary has not been reset, under these conditions.

Changes

Error Boundary Query Remount Retry Behavior

Layer / File(s) Summary
Retry prevention condition refinement
packages/react-query/src/errorBoundaryUtils.ts
ensurePreventErrorBoundaryRetry replaces an unconditional reset check with a compound condition that also validates suspense mode or observer presence, refining when retries are prevented.
Remount retry test verification
packages/react-query/src/__tests__/QueryResetErrorBoundary.test.tsx
Test descriptions are updated from "no retry" to "retry on remount," and test bodies now track query execution count via fetchCount, asserting queries execute twice and render data on the second mount; onReset/shouldReset timing is adjusted accordingly.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A boundary reset, or so we thought—
Now queries retry as they ought!
With suspense and observers to see,
Remounting brings data for thee.
No manual reset, just mount naturally! 🌱

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description covers the key changes and objectives but is missing checklist items and release impact declaration required by the template. Complete the checklist items (Contributing guide compliance and local testing) and specify release impact (changeset needed or dev-only).
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: retry error boundary queries on remount' directly and clearly describes the main change—enabling queries caught by error boundaries to retry when components remount.
Linked Issues check ✅ Passed The code changes directly address #2712 by allowing non-suspense error-boundary queries to retry on remount after unmounting the failed observer, while preserving retry suppression during observer presence.
Out of Scope Changes check ✅ Passed All changes are directly scoped to error boundary retry behavior: test updates validate the new retry-on-remount behavior, and the utility function implements the core retry logic for #2712.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 and usage tips.

@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.

🧹 Nitpick comments (1)
packages/react-query/src/__tests__/QueryResetErrorBoundary.test.tsx (1)

483-488: ⚡ Quick win

Test doesn't exercise the "previous reset" it claims.

shouldReset is set to true (Line 484) and back to false (Line 491) with no fireEvent.click in between, so onReset (and thus reset()) never fires while shouldReset is true. The middle block is dead code that only re-asserts the boundary is still shown; the named "after a previous reset" path is never executed. Add the missing interaction so a reset-based retry actually occurs before the final remount-without-reset assertion.

💚 Trigger the reset-based retry in the middle block
       succeed = false
       shouldReset = true

+      fireEvent.click(rendered.getByText('retry'))
       await vi.advanceTimersByTimeAsync(11)
       expect(rendered.getByText('error boundary')).toBeInTheDocument()
       expect(rendered.getByText('retry')).toBeInTheDocument()
With the click, `onReset` runs `reset()` (since `shouldReset` is `true`), causing a reset-based retry that fails again (`succeed` still `false`); `useClearResetErrorBoundary` then clears the reset on remount, so the final block (`shouldReset = false`) genuinely tests retry-on-remount without a reset.
🤖 Prompt for 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.

In `@packages/react-query/src/__tests__/QueryResetErrorBoundary.test.tsx` around
lines 483 - 488, The test sets shouldReset = true then resets it to false
without triggering the reset path, so add the missing user interaction to invoke
onReset/reset(): after setting shouldReset = true and before setting shouldReset
= false, call the UI interaction that clicks the retry button (e.g.,
fireEvent.click(rendered.getByText('retry')) or the equivalent used in this
test) so that reset() is executed while shouldReset is true; this will exercise
the "previous reset" path and allow the final block (shouldReset = false) to
truly test retry-on-remount without a reset.
🤖 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.

Nitpick comments:
In `@packages/react-query/src/__tests__/QueryResetErrorBoundary.test.tsx`:
- Around line 483-488: The test sets shouldReset = true then resets it to false
without triggering the reset path, so add the missing user interaction to invoke
onReset/reset(): after setting shouldReset = true and before setting shouldReset
= false, call the UI interaction that clicks the retry button (e.g.,
fireEvent.click(rendered.getByText('retry')) or the equivalent used in this
test) so that reset() is executed while shouldReset is true; this will exercise
the "previous reset" path and allow the final block (shouldReset = false) to
truly test retry-on-remount without a reset.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4dbdcf70-0ac8-4daa-9280-b3a229835da0

📥 Commits

Reviewing files that changed from the base of the PR and between d5630c9 and b1e18fd.

📒 Files selected for processing (2)
  • packages/react-query/src/__tests__/QueryResetErrorBoundary.test.tsx
  • packages/react-query/src/errorBoundaryUtils.ts

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@nx-cloud

nx-cloud Bot commented May 29, 2026

Copy link
Copy Markdown

🤖 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 9bb9aa6

Command Status Duration Result
nx affected --targets=test:sherif,test:knip,tes... ❌ Failed 2m 53s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 28s View ↗

☁️ Nx Cloud last updated this comment at 2026-05-29 15:41:05 UTC

@TkDodo TkDodo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

you’re changing tests to match the new behaviour ? additionally, there are more failing tests. The problem is react rendering the component an additional time even after an error has been thrown before the errorBoundary renders.

@TkDodo TkDodo closed this May 29, 2026
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.

Errored queries caught by ErrorBoundary are not retried on mount

2 participants