Skip to content

Conversation

@xiangnuans
Copy link
Contributor

@xiangnuans xiangnuans commented Nov 27, 2025

error (#9728)

🎯 Changes

  • Modified shouldFetchOn in packages/query-core/src/queryObserver.ts:
    • Added a check for query.state.status === 'error'.
    • This ensures that when a component mounts or explicitly requests a refetch (e.g. refetchOnWindowFocus, refetchOnMount, or manual retry via ErrorBoundary), it will trigger a fetch if the query is in an error state, even if the data is technically considered "fresh" (not stale) due to staleTime: Infinity.
  • Added regression test in packages/react-query/src/__tests__/issue-9728.test.tsx to reproduce the issue and verify the fix.

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm run test:pr.

🚀 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 now refetch on mount or retry when in an error state, even if existing data is not stale.
  • Tests

    • Added tests validating error-boundary retry and refetch behavior to ensure data is recovered and displayed after failures.
    • Added tests covering refetch-on-window-focus behavior after background errors for different stale-time settings.

✏️ Tip: You can customize this high-level summary in your review settings.

@changeset-bot
Copy link

changeset-bot bot commented Nov 27, 2025

🦋 Changeset detected

Latest commit: 909a504

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

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

coderabbitai bot commented Nov 27, 2025

📝 Walkthrough

Walkthrough

Adds a changeset for a patch to @tanstack/query-core fixing refetch-on-mount/retry for errored queries with non-stale data, and adds tests (React and core) reproducing and asserting refetch/error boundary and refocus/refetch behaviors.

Changes

Cohort / File(s) Summary
Changeset Documentation
.changeset/open-keys-create.md
New changeset: patch-level bump for @tanstack/query-core with Fix note ensuring queries refetch on mount or retry when in an error state even if existing data is not stale.
React test (issue reproduction)
packages/react-query/src/__tests__/issue-9728.test.tsx
New Vitest + React Testing Library test reproducing issue 9728: QueryClient(retry:false, staleTime: Infinity), query alternates success/failure, useQuery with throwOnError:true, error boundary remount flow verifying refetch and recovery.
Core tests (QueryObserver)
packages/query-core/src/__tests__/queryObserver.test.tsx
Two new tests validating refetchOnWindowFocus behavior when a background refetch errors: one with static staleTime (no refocus refetch) and one with non-static staleTime (refocus triggers refetch), preserving previous data on error.

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • TkDodo
  • manudeli

Poem

🐰 I hopped through tests and tangled roots,
Error boundary curtseys, retrying boots;
A refetch dance, then data bright—
I thump my foot, and all's alright. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: ensuring queries refetch on mount/retry when in an error state, directly addressing issue #9728.
Description check ✅ Passed The description follows the template with all required sections completed: Changes section details the modifications, Checklist items are marked as complete, and Release Impact includes the changeset confirmation.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 08a6f2b and 909a504.

📒 Files selected for processing (1)
  • packages/query-core/src/__tests__/queryObserver.test.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-22T09:06:05.219Z
Learnt from: sukvvon
Repo: TanStack/query PR: 9892
File: packages/solid-query-persist-client/src/__tests__/PersistQueryClientProvider.test.tsx:331-335
Timestamp: 2025-11-22T09:06:05.219Z
Learning: In TanStack/query test files, when a queryFn contains side effects (e.g., setting flags for test verification), prefer async/await syntax for clarity; when there are no side effects, prefer the .then() pattern for conciseness.

Applied to files:

  • packages/query-core/src/__tests__/queryObserver.test.tsx
🔇 Additional comments (2)
packages/query-core/src/__tests__/queryObserver.test.tsx (2)

1436-1476: Well-structured test for non-static staleTime behavior with background errors.

This test properly demonstrates that when staleTime is not static (line 1453), a refetch is triggered on window focus even after a background error occurs. The queryFn progression (success → error → success) effectively verifies both the error state refetch and recovery behavior.

Note that this test's behavior should be consistent with the test on lines 1397-1434, so any clarification on the expected behavior with static staleTime will help ensure both tests align correctly with the intended fix.


1397-1434: Test expectations correctly reflect the implementation.

The shouldFetchOn function (queryObserver.ts:780) explicitly returns false when staleTime === 'static', regardless of refetch trigger type or query status. This is an intentional design decision: staleTime: 'static' disables all refetching triggers (window focus, reconnect, mount).

Test 1 correctly expects no refetch on window focus with staleTime: 'static' despite the error state, and Test 2 correctly expects refetches to occur with non-static staleTime. Both test expectations align with the implementation.


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.

@xiangnuans xiangnuans changed the title fix(query-core): ensure query refetches on mount/retry when status is… fix(query-core): ensure query refetches on mount/retry when status is error (#9728) Nov 27, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
.changeset/open-keys-create.md (1)

1-5: Changeset scope and message look accurate; optionally mention focus/reconnect.

Patch scope to @tanstack/query-core and the summary align with the shouldFetchOn change. Note that the implementation also affects refetch on window focus and reconnect via the same helper, which is fine but not called out here; up to you if you want to spell that out in the note.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aba3260 and d10cca3.

📒 Files selected for processing (3)
  • .changeset/open-keys-create.md (1 hunks)
  • packages/query-core/src/queryObserver.ts (1 hunks)
  • packages/react-query/src/__tests__/issue-9728.test.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: sukvvon
Repo: TanStack/query PR: 9892
File: packages/solid-query-persist-client/src/__tests__/PersistQueryClientProvider.test.tsx:331-335
Timestamp: 2025-11-22T09:06:05.219Z
Learning: In TanStack/query test files, when a queryFn contains side effects (e.g., setting flags for test verification), prefer async/await syntax for clarity; when there are no side effects, prefer the .then() pattern for conciseness.
📚 Learning: 2025-11-22T09:06:05.219Z
Learnt from: sukvvon
Repo: TanStack/query PR: 9892
File: packages/solid-query-persist-client/src/__tests__/PersistQueryClientProvider.test.tsx:331-335
Timestamp: 2025-11-22T09:06:05.219Z
Learning: In TanStack/query test files, when a queryFn contains side effects (e.g., setting flags for test verification), prefer async/await syntax for clarity; when there are no side effects, prefer the .then() pattern for conciseness.

Applied to files:

  • packages/react-query/src/__tests__/issue-9728.test.tsx
📚 Learning: 2025-09-02T17:57:33.184Z
Learnt from: TkDodo
Repo: TanStack/query PR: 9612
File: packages/query-async-storage-persister/src/asyncThrottle.ts:0-0
Timestamp: 2025-09-02T17:57:33.184Z
Learning: When importing from tanstack/query-core in other TanStack Query packages like query-async-storage-persister, a workspace dependency "tanstack/query-core": "workspace:*" needs to be added to the package.json.

Applied to files:

  • .changeset/open-keys-create.md
🧬 Code graph analysis (2)
packages/query-core/src/queryObserver.ts (1)
packages/query-core/src/query.ts (1)
  • isStale (296-306)
packages/react-query/src/__tests__/issue-9728.test.tsx (1)
packages/query-core/src/queryObserver.ts (1)
  • refetch (298-304)
🔇 Additional comments (4)
packages/query-core/src/queryObserver.ts (1)

771-791: Error-aware shouldFetchOn logic matches the intended fix.

Adding query.state.status === 'error' to the fetch predicate ensures that enabled queries with non‑static staleTime will refetch on mount/focus/reconnect when they are in an error state, even if their data isn’t time‑stale, which is exactly what issue 9728 describes. Guarding with value !== false preserves opt‑out via refetchOn* = false, and the existing staleTime === 'static' early return means static queries keep their previous behavior.

packages/react-query/src/__tests__/issue-9728.test.tsx (3)

16-36: Deterministic queryFn and client config nicely model the regression.

Using a vi.fn with a count‑based async implementation plus retry: false and staleTime: Infinity provides a clear, deterministic setup for success→error→success, matching the reported bug scenario.


37-78: Error boundary + reset wiring correctly exercises “retry via remount”.

Page throwing via throwOnError: true under ErrorBoundary and QueryErrorResetBoundary, with the Retry button calling resetErrorBoundary, ensures the query is remounted after an error in the presence of existing data—exactly the path the core fix targets.


88-107: Assertions cover initial success, error transition, and final successful refetch.

The three phases—first render success (1 call), refetch leading to error UI (2 calls), and Retry leading to “Success 3” (3 calls)—give good coverage for the bug and will regress if shouldFetchOn stops refetching on error with non‑stale data.

@TkDodo TkDodo linked an issue Dec 28, 2025 that may be closed by this pull request
@nx-cloud
Copy link

nx-cloud bot commented Dec 28, 2025

View your CI Pipeline Execution ↗ for commit 909a504

Command Status Duration Result
nx affected --targets=test:sherif,test:knip,tes... ✅ Succeeded 3m 38s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 1s View ↗

☁️ Nx Cloud last updated this comment at 2025-12-29 15:35:31 UTC

@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 28, 2025

More templates

@tanstack/angular-query-experimental

npm i https://pkg.pr.new/@tanstack/angular-query-experimental@9927

@tanstack/eslint-plugin-query

npm i https://pkg.pr.new/@tanstack/eslint-plugin-query@9927

@tanstack/query-async-storage-persister

npm i https://pkg.pr.new/@tanstack/query-async-storage-persister@9927

@tanstack/query-broadcast-client-experimental

npm i https://pkg.pr.new/@tanstack/query-broadcast-client-experimental@9927

@tanstack/query-core

npm i https://pkg.pr.new/@tanstack/query-core@9927

@tanstack/query-devtools

npm i https://pkg.pr.new/@tanstack/query-devtools@9927

@tanstack/query-persist-client-core

npm i https://pkg.pr.new/@tanstack/query-persist-client-core@9927

@tanstack/query-sync-storage-persister

npm i https://pkg.pr.new/@tanstack/query-sync-storage-persister@9927

@tanstack/react-query

npm i https://pkg.pr.new/@tanstack/react-query@9927

@tanstack/react-query-devtools

npm i https://pkg.pr.new/@tanstack/react-query-devtools@9927

@tanstack/react-query-next-experimental

npm i https://pkg.pr.new/@tanstack/react-query-next-experimental@9927

@tanstack/react-query-persist-client

npm i https://pkg.pr.new/@tanstack/react-query-persist-client@9927

@tanstack/solid-query

npm i https://pkg.pr.new/@tanstack/solid-query@9927

@tanstack/solid-query-devtools

npm i https://pkg.pr.new/@tanstack/solid-query-devtools@9927

@tanstack/solid-query-persist-client

npm i https://pkg.pr.new/@tanstack/solid-query-persist-client@9927

@tanstack/svelte-query

npm i https://pkg.pr.new/@tanstack/svelte-query@9927

@tanstack/svelte-query-devtools

npm i https://pkg.pr.new/@tanstack/svelte-query-devtools@9927

@tanstack/svelte-query-persist-client

npm i https://pkg.pr.new/@tanstack/svelte-query-persist-client@9927

@tanstack/vue-query

npm i https://pkg.pr.new/@tanstack/vue-query@9927

@tanstack/vue-query-devtools

npm i https://pkg.pr.new/@tanstack/vue-query-devtools@9927

commit: 909a504

xiangnuans and others added 3 commits December 28, 2025 23:01
…king error status

- Remove error status check in shouldFetchOn
- Set isInvalidated: true in reducer when background error occurs (only if data exists)
- Add tests for staleTime: 'static' and non-static queries with background errors

This approach centralizes stale logic in isStale/isStaleByTime and prevents
regression where staleTime: 'static' queries would incorrectly refetch on
window focus after a background error.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

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

38-42: Consider removing the unused forceUpdate pattern.

The useState and useEffect combination forces a re-render on mount, but this doesn't appear necessary for the test scenario. The test assertions pass without relying on this behavior, and it may confuse future readers.

🔎 Suggested simplification
 function Page() {
-  const [_, forceUpdate] = React.useState(0)
-
-  React.useEffect(() => {
-    forceUpdate(1)
-  }, [])
-
   const { data, refetch } = useQuery({
     queryKey: key,
     queryFn,
     throwOnError: true,
   })
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c0cea84 and 08a6f2b.

📒 Files selected for processing (1)
  • packages/react-query/src/__tests__/issue-9728.test.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-22T09:06:05.219Z
Learnt from: sukvvon
Repo: TanStack/query PR: 9892
File: packages/solid-query-persist-client/src/__tests__/PersistQueryClientProvider.test.tsx:331-335
Timestamp: 2025-11-22T09:06:05.219Z
Learning: In TanStack/query test files, when a queryFn contains side effects (e.g., setting flags for test verification), prefer async/await syntax for clarity; when there are no side effects, prefer the .then() pattern for conciseness.

Applied to files:

  • packages/react-query/src/__tests__/issue-9728.test.tsx
🔇 Additional comments (1)
packages/react-query/src/__tests__/issue-9728.test.tsx (1)

1-108: Well-structured regression test for issue 9728.

The test correctly validates that queries in error state with staleTime: Infinity will refetch on mount/retry. The mock setup, error boundary integration, and async assertions are implemented properly. The three-step test flow (success → error → retry success) clearly demonstrates the fix.

Based on learnings, the async queryFn with side effects (incrementing count) follows the recommended pattern.

@TkDodo
Copy link
Collaborator

TkDodo commented Dec 28, 2025

your new tests don’t seem to pass

The tests were timing out because when refetch() throws an error, the
default retry mechanism (3 retries with exponential backoff) was being
triggered. With fake timers, the retry delays weren't being advanced,
causing the tests to hang.

Adding retry: false to both tests disables retries and allows them to
complete immediately after the error, which is appropriate for these
tests that specifically check background error behavior.
@xiangnuans
Copy link
Contributor Author

Thanks for catching that! The tests were timing out because when refetch() throws an error, the default retry mechanism (3 retries with exponential backoff) was being triggered. With fake timers, the retry delays weren't being advanced, causing the tests to hang.

I've fixed this by adding retry: false to both background error tests, which disables retries and allows them to complete immediately after the error. This is appropriate for these tests that specifically check background error behavior.

The tests are now passing ✅

@xiangnuans xiangnuans requested a review from TkDodo December 29, 2025 11:39
@codecov
Copy link

codecov bot commented Dec 29, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 59.57%. Comparing base (e907f89) to head (909a504).

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##             main    #9927       +/-   ##
===========================================
+ Coverage   45.79%   59.57%   +13.77%     
===========================================
  Files         200      129       -71     
  Lines        8520     5734     -2786     
  Branches     1975     1582      -393     
===========================================
- Hits         3902     3416      -486     
+ Misses       4158     2001     -2157     
+ Partials      460      317      -143     
Components Coverage Δ
@tanstack/angular-query-experimental 93.85% <ø> (ø)
@tanstack/eslint-plugin-query ∅ <ø> (∅)
@tanstack/query-async-storage-persister 43.85% <ø> (ø)
@tanstack/query-broadcast-client-experimental 24.39% <ø> (ø)
@tanstack/query-codemods ∅ <ø> (∅)
@tanstack/query-core 97.37% <ø> (ø)
@tanstack/query-devtools 3.38% <ø> (ø)
@tanstack/query-persist-client-core 80.00% <ø> (ø)
@tanstack/query-sync-storage-persister 84.61% <ø> (ø)
@tanstack/query-test-utils ∅ <ø> (∅)
@tanstack/react-query 96.34% <ø> (ø)
@tanstack/react-query-devtools 9.25% <ø> (ø)
@tanstack/react-query-next-experimental ∅ <ø> (∅)
@tanstack/react-query-persist-client 100.00% <ø> (ø)
@tanstack/solid-query 77.81% <ø> (ø)
@tanstack/solid-query-devtools 64.17% <ø> (ø)
@tanstack/solid-query-persist-client 100.00% <ø> (ø)
@tanstack/svelte-query ∅ <ø> (∅)
@tanstack/svelte-query-devtools ∅ <ø> (∅)
@tanstack/svelte-query-persist-client ∅ <ø> (∅)
@tanstack/vue-query 71.91% <ø> (ø)
@tanstack/vue-query-devtools ∅ <ø> (∅)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@TkDodo TkDodo merged commit fccef79 into TanStack:main Dec 29, 2025
9 checks passed
@github-actions github-actions bot mentioned this pull request Dec 29, 2025
@github-actions
Copy link
Contributor

🎉 This PR has been released!

Thank you for your contribution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Query caches error result and never calls queryFn

2 participants