Skip to content

fix(react-query): retry errored queries that mount after the error boundary reset wave 🤖🤖🤖 - #11916

Open
wspperrimh wants to merge 1 commit into
TanStack:mainfrom
wspperrimh:fix/error-boundary-reset-per-query
Open

wspperrimh wants to merge 1 commit into
TanStack:mainfrom
wspperrimh:fix/error-boundary-reset-per-query

Conversation

@wspperrimh

@wspperrimh wspperrimh commented Oct 4, 2026 •

Copy link
Copy Markdown

Fixes #2712

🎯 Changes

QueryErrorResetBoundary kept a single shared isReset flag. The first query that mounted after reset() cleared it in its mount effect, so any other errored query that mounted later in the boundary — e.g. once its parent re-rendered it — no longer saw the reset, kept retryOnMount: false, and threw its stale error straight back into the boundary.

The boundary now tracks a reset generation and which generation each query hash last cleared. isReset(queryHash) and clearReset(queryHash) take an optional query hash so one query can no longer consume the reset on behalf of its siblings. Callers that don't pass a hash keep the previous shared-flag behavior, so the public API is unchanged.

Applied the same fix in react-query and preact-query, and added a regression test in both packages: a healthy sibling query mounts on the reset wave while an errored query mounts later — the errored query must still retry. The test fails on the previous implementation.

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested code changes locally with pnpm run test:pr, or these tests do not apply to this pull request.
  • I have followed the AI contribution policy and fully understand the code in this pull request, including any code generated with AI assistance.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

Summary by CodeRabbit

  • Bug Fixes
    • Queries that remount after an error-boundary reset can now retry independently, even when sibling queries mount first. This prevents one query from consuming another’s reset and allows the errored query to render successfully once its request succeeds. Applies to React Query and Preact Query.

… the error boundary reset wave

Queries mounting while the reset flag was pending each cleared the shared
flag in their mount effect, so the first mounted query consumed the reset
before other errored queries could observe it. Track a reset generation
and which generation each query last cleared, so every errored query
inside the boundary retries once after a reset even when it mounts after
siblings already consumed the shared wave.

Fixes TanStack#2712
@changeset-bot

changeset-bot Bot commented Oct 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e23f009

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

This PR includes changesets to release 24 packages
Name Type
@tanstack/react-query Patch
@tanstack/preact-query Patch
@tanstack/react-query-devtools Patch
@tanstack/react-query-next-experimental Patch
@tanstack/react-query-persist-client Patch
@tanstack/preact-query-devtools Patch
@tanstack/preact-query-persist-client Patch
@tanstack/angular-query-experimental Patch
@tanstack/eslint-plugin-query Patch
@tanstack/query-async-storage-persister Patch
@tanstack/query-broadcast-client-experimental Patch
@tanstack/query-core Patch
@tanstack/query-devtools Patch
@tanstack/query-persist-client-core Patch
@tanstack/query-sync-storage-persister Patch
@tanstack/solid-query-devtools Patch
@tanstack/solid-query-persist-client Patch
@tanstack/solid-query Patch
@tanstack/vue-query Patch
@tanstack/lit-query Patch
@tanstack/svelte-query Patch
@tanstack/svelte-query-devtools Patch
@tanstack/vue-query-devtools Patch
@tanstack/svelte-query-persist-client 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

@coderabbitai

coderabbitai Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: TanStack/query/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: bd5d1dd9-967e-40bf-b9a0-306c7db4b245
📥 Commits

Reviewing files that changed from the base of the PR and between eaa75f4 and e23f009.

📒 Files selected for processing (13)
  • .changeset/eager-dingos-retry.md
  • packages/preact-query/src/QueryErrorResetBoundary.tsx
  • packages/preact-query/src/__tests__/QueryResetErrorBoundary.test.tsx
  • packages/preact-query/src/errorBoundaryUtils.ts
  • packages/preact-query/src/suspense.ts
  • packages/preact-query/src/useBaseQuery.ts
  • packages/preact-query/src/useQueries.ts
  • packages/react-query/src/QueryErrorResetBoundary.tsx
  • packages/react-query/src/__tests__/QueryResetErrorBoundary.test.tsx
  • packages/react-query/src/errorBoundaryUtils.ts
  • packages/react-query/src/suspense.ts
  • packages/react-query/src/useBaseQuery.ts
  • packages/react-query/src/useQueries.ts

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


📝 Walkthrough

Walkthrough

React Query and Preact Query now track error-boundary resets by query hash. Their retry checks and reset-clearing calls use query-specific state. Regression tests cover an errored query remounting after a sibling query has mounted during the reset.

Changes

Query reset handling

Layer / File(s) Summary
Track reset generations
packages/react-query/src/QueryErrorResetBoundary.tsx, packages/preact-query/src/QueryErrorResetBoundary.tsx
Both reset boundaries accept an optional query hash and track reset generations and per-query cleared generations.
Apply reset state per query
packages/react-query/src/errorBoundaryUtils.ts, packages/react-query/src/suspense.ts, packages/react-query/src/useBaseQuery.ts, packages/react-query/src/useQueries.ts, packages/preact-query/src/errorBoundaryUtils.ts, packages/preact-query/src/suspense.ts, packages/preact-query/src/useBaseQuery.ts, packages/preact-query/src/useQueries.ts
Retry checks, error checks, and reset-clearing calls now use the relevant query hash or hashes.
Verify remount retries
packages/react-query/src/__tests__/QueryResetErrorBoundary.test.tsx, packages/preact-query/src/__tests__/QueryResetErrorBoundary.test.tsx, .changeset/eager-dingos-retry.md
Regression tests check that the errored query renders data after remounting and succeeding. The changeset requests patch releases for both packages.

Priority: ➖ Normal

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

Change: Bug fix · Severity of issue fixed: Medium

Possibly related PRs

  • TanStack/query#10921: Addresses the same reset behavior and adds related regression tests, using reset counts for query instances.

Suggested reviewers: sukvvon

Merge Risk: ⚪ Minimal · up to e23f0

The remount retry regression is covered, and no actionable merge-blocking issue remains.

Security Architecture Review

Security architecture risk: 🔵 Low · up to e23f0

The change improves retry isolation and preserves existing zero-argument API usage. The main concern is that reset bookkeeping retains query identities indefinitely in long-lived boundaries, potentially increasing memory consumption. No new authorization bypass or attacker-accessible exploit was established.

Retained concerns

  • Low · reliability · observed: The new per-query registry retains every cleared query hash without individual retirement. Internal clearing paths insert records rather than remove them, so long-lived boundaries—and especially the module-level default context—can accumulate records independently of query unmounting or cache removal. This introduces an availability-relevant resource-lifecycle concern compared with the previous constant-size flag.
Security review details

Security Blast Radius

  • inferred — The directly supported scope is the hosting runtime's reset value: one explicit boundary, or the shared default value within a package module instance. The default value is not keyed by QueryClient, so separate clients using that default can share hash records. This default-context sharing predates the PR, while persistent per-hash storage is new. Production tenant and deployment exposure was not established.

Security Findings and Attack Paths

  • inferred — A host application that produces many distinct query hashes can grow the retained registry. Exploitation would additionally require an attacker-influenced path capable of sustaining that churn in a sufficiently long-lived runtime; such a path was not demonstrated. The supported concern is resource retention, not a verified denial-of-service vulnerability.

Trust Boundaries and Controls

  • observed — Reset decisions use query-hash identity consistently across retry prevention and error throwing. The public API accepts strings rather than authenticated identities; this identifies lifecycle records, not tenants or permissions. Error throwing still requires an errored, non-fetching query and the existing suspense or throwOnError condition.

Resilience and Maintainability Implications

  • observed — The new lifecycle preserves an established query's reset across sibling cleanup, improving recovery isolation. The unseen-hash fallback still permits shared consumption, as in the previous flag-based implementation; it is not an established new control bypass.

Hardening Proposals

  • proposed — Define lifecycle-aware retirement or bounded reset bookkeeping that preserves the late-remount guarantee. Simply deleting records on component unmount would restore the sibling-consumption problem, so resource cleanup must account for queries still entitled to observe an earlier reset.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning Issue [#2712] expects an errored query to retry when it mounts again, honoring retryOnMount. In errorBoundaryUtils.ts, ensurePreventErrorBoundaryRetry still sets options.retryOnMount = false w… Implement and test the #2712 remount scenario so an errored query retries when retryOnMount allows it, without causing error-boundary retry loops.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 12 functions across 12 files. (1 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: retrying errored queries that mount after an error-boundary reset. The emojis add unnecessary noise, but the title remains specific and relevant.
Description check ✅ Passed The description explains the bug, the fix, and the regression tests. It includes all required template sections and completes the checklist and release-impact information.
Out of Scope Changes check ✅ Passed The reset-generation tracking, query-scoped reset checks, React and Preact parity, regression tests, and changeset all support the error-boundary retry behavior in #2712. No unrelated changes are evid…
Full details: Linked Issues check

Explanation

Issue [#2712] expects an errored query to retry when it mounts again, honoring retryOnMount. In errorBoundaryUtils.ts, ensurePreventErrorBoundaryRetry still sets options.retryOnMount = false when isReset(options.queryHash) is false. A remount without reset() therefore still does not retry. The new regression test covers a remount after a reset wave, not the issue's remount without a reset.

Full details: Docstring Coverage

Explanation

Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 12 functions across 12 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autopilot · 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.

This branch has not been deployed

No deployments
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

1 participant