Skip to content

fix(query-core): snapshot resetQueries match set before mutating state#10765

Open
spokodev wants to merge 1 commit into
TanStack:mainfrom
spokodev:fix/reset-queries-snapshot-before-mutate
Open

fix(query-core): snapshot resetQueries match set before mutating state#10765
spokodev wants to merge 1 commit into
TanStack:mainfrom
spokodev:fix/reset-queries-snapshot-before-mutate

Conversation

@spokodev
Copy link
Copy Markdown

@spokodev spokodev commented May 23, 2026

Closes #10705.

What was broken

queryClient.resetQueries({ predicate: q => q.state.status === 'error' }) reset the matched queries but never re-fetched them — they stayed stuck in pending forever.

Root cause

resetQueries ran the caller's filter twice:

  1. First, to pick the queries to reset.
  2. Second, inside the refetchQueries({ type: 'active', ...filters }) call, to pick the queries to re-fetch.

query.reset() mutates each query's state — for example, the status flips from "error" to "pending". When filters contains a state-based predicate like q => q.state.status === 'error', the second pass evaluates against the already-mutated state and the matched set collapses, so the re-fetch step silently does nothing.

The original issue author traced this exactly: #10705

Fix

Snapshot the matched queries before calling reset(), then refetch the same set by identity (matchedQueries.includes(query)), still scoped to type: 'active'. Query references are stable across reset(), so the identity predicate is a faithful replacement for the caller's filter without the state-mutation hazard.

return notifyManager.batch(() => {
  const matchedQueries = queryCache.findAll(filters)
  matchedQueries.forEach((query) => {
    query.reset()
  })
  return this.refetchQueries(
    {
      type: 'active',
      predicate: (query) => matchedQueries.includes(query),
    },
    options,
  )
})

Test

Added a regression test in queryClient.test.tsx covering the exact scenario from the issue: two active queries (one errored, one successful), call resetQueries({ predicate: status === 'error' }), assert the errored query's queryFn was called once and the successful one's wasn't.

  • Fails on main (errored queryFn called 0 times — bug behaviour).
  • Passes with the fix.

Full queryClient.test.tsx suite: 108 passed (one new test added). Lint clean on changed files.

Note on scope

The same two-pass pattern exists in invalidateQueries, but invalidate() only flips isInvalidated (which the caller's predicate is unlikely to key on) and the refetchType: 'none' short-circuit covers the obvious case. Leaving that alone to keep this PR scoped to the reported bug.

Summary by CodeRabbit

  • Bug Fixes

    • Fixed query reset with predicates to correctly refetch only matching queries, preventing unintended query refetches due to state mutations.
  • Tests

    • Added regression test for predicate-based query reset and refetch behavior.

Review Change Stack

Fixes TanStack#10705.

`resetQueries` ran the caller's filter twice: once to pick queries to
reset, then a second time inside `refetchQueries` to pick queries to
re-fetch. The first call mutates each query's state (e.g. status flips
from "error"/"success" to "pending"), so when the filter uses a
state-based predicate the second pass no longer matches the same set
and the refetch silently skips the queries we just reset.

The fix snapshots the matched queries before calling `reset()`, then
refetches the same set by identity (`matchedQueries.includes(query)`),
still scoped to active queries. Query instances are stable across
reset, so the identity predicate is a faithful replacement for the
caller's filter without the state-mutation hazard.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 23, 2026

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 559c1e5e-5d83-4631-a415-8ac77b127345

📥 Commits

Reviewing files that changed from the base of the PR and between 3f10705 and 020ae15.

📒 Files selected for processing (2)
  • packages/query-core/src/__tests__/queryClient.test.tsx
  • packages/query-core/src/queryClient.ts
 _____________________________________________________________
< 🥕 I brought carrots. You brought corner cases. Let's party. >
 -------------------------------------------------------------
  \
   \   (\__/)
       (•ㅅ•)
       /   づ
✨ 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.

Tip

CodeRabbit can generate a title for your PR based on the changes.

Add @coderabbitai placeholder anywhere in the title of your PR and CodeRabbit will replace it with a title based on the changes in the PR. You can change the placeholder by changing the reviews.auto_title_placeholder setting.

@nx-cloud
Copy link
Copy Markdown

nx-cloud Bot commented May 23, 2026

View your CI Pipeline Execution ↗ for commit 020ae15

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

☁️ Nx Cloud last updated this comment at 2026-05-23 13:27:36 UTC

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 23, 2026

More templates

@tanstack/angular-query-experimental

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

@tanstack/eslint-plugin-query

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

@tanstack/lit-query

npm i https://pkg.pr.new/@tanstack/lit-query@10765

@tanstack/preact-query

npm i https://pkg.pr.new/@tanstack/preact-query@10765

@tanstack/preact-query-devtools

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

@tanstack/preact-query-persist-client

npm i https://pkg.pr.new/@tanstack/preact-query-persist-client@10765

@tanstack/query-async-storage-persister

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

@tanstack/query-broadcast-client-experimental

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

@tanstack/query-core

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

@tanstack/query-devtools

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

@tanstack/query-persist-client-core

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

@tanstack/query-sync-storage-persister

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

@tanstack/react-query

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

@tanstack/react-query-devtools

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

@tanstack/react-query-next-experimental

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

@tanstack/react-query-persist-client

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

@tanstack/solid-query

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

@tanstack/solid-query-devtools

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

@tanstack/solid-query-persist-client

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

@tanstack/svelte-query

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

@tanstack/svelte-query-devtools

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

@tanstack/svelte-query-persist-client

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

@tanstack/vue-query

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

@tanstack/vue-query-devtools

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

commit: 020ae15

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.

resetQueries method does not trigger refetch on errored queries

1 participant