Skip to content

Conversation

@nwrahnema
Copy link

@nwrahnema nwrahnema commented Dec 16, 2025

🎯 Changes

In 1b54538, setOptions was changed to call notifyListeners which eventually leads to QueriesObserver.setQueries

  1. Updating #observerMatches
  2. Calling setOptions which leads to #notify being called
  3. Updating #result

This is an issue when #notify is called before the #result is updated, as #trackResult assumes these two are the same length, which may not be the case if the number of queries changed. When the length increases, observerResult becomes undefined and the function throws an exception.

Fix by moving the #observerMatches assignment later in the function, next to the #observers and #result assignment. I don't know the full nuances of this code so please advise if there's a better solution.

✅ 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
    • Fixed a race condition in useQueries that occurred when the number of queries changed, ensuring proper observer state updates.

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

In 1b54538, `setOptions` was changed to call `notifyListeners` which
eventually leads to `QueriesObserver.setQueries`

1. Updating `#observerMatches`
2. Calling `setOptions` which leads to `#notify` being called
3. Updating `#result`

This is an issue when `#notify` is called before the `#result` is
updated, as `#trackResult` assumes these two are the same length, which
may not be the case if the number of queries changed. When the length
increases, `observerResult` becomes `undefined` and the function throws
an exception.

Fix by moving the `#observerMatches` assignment later in the function,
next to the `#observers` and `#result` assignment.
@changeset-bot
Copy link

changeset-bot bot commented Dec 16, 2025

🦋 Changeset detected

Latest commit: 13e69b0

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 Dec 16, 2025

Walkthrough

This PR patches @tanstack/query-core to fix a race condition in useQueries when the number of queries changes. The fix modifies when observerMatches is updated in queriesObserver.ts—shifting from unconditional assignment to conditional assignment only during structural changes.

Changes

Cohort / File(s) Change Summary
Changeset documentation
.changeset/orange-flowers-post.md
Added patch version bump entry for @tanstack/query-core describing race condition fix in useQueries (#9971)
Core observer fix
packages/query-core/src/queriesObserver.ts
Moved observerMatches update from unconditional assignment to conditional assignment within structural-change branch, ensuring observer matches only updates during actual structural changes

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~15 minutes

  • The code change itself is focused and minimal (one assignment relocation)
  • Verify the race condition scenario is properly addressed by the conditional timing change
  • Ensure no regressions in non-structural-change update paths

Possibly related PRs

  • TanStack/query#9639: Also modifies queriesObserver.ts to adjust observer matching and structural-change detection logic timing

Suggested labels

package: query-core

Suggested reviewers

  • TkDodo

Poem

🐰 Queries raced ahead with hearts so wild,
Timing stumbled, observers beguiled,
But now they sync when structure does sway,
No more race conditions will ruin the day!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main fix: addressing a mismatch between queriesObserver result and observer length.
Description check ✅ Passed The description follows the template with complete sections: detailed explanation of the issue, full checklist completion, and proper release impact marking.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f15b7fc and 13e69b0.

📒 Files selected for processing (2)
  • .changeset/orange-flowers-post.md (1 hunks)
  • packages/query-core/src/queriesObserver.ts (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.
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.
📚 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:

  • .changeset/orange-flowers-post.md
📚 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/orange-flowers-post.md
🔇 Additional comments (2)
.changeset/orange-flowers-post.md (1)

1-5: LGTM!

The changeset correctly describes the fix and appropriately uses a patch version bump for this bug fix.

packages/query-core/src/queriesObserver.ts (1)

136-136: Fix correctly addresses the race condition.

Moving the #observerMatches assignment inside the hasStructuralChange block ensures that when setOptions (line 112) triggers an early notify via a listener, both #observerMatches and #result still have matching lengths (both reflecting the old state). This prevents the index-out-of-bounds error in #trackResult that occurred when #observerMatches was updated unconditionally before the setOptions calls.


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.

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.

1 participant