Skip to content

fix(query-core): distinguish query keys differing only by a Date in partialMatchKey#10982

Open
YESHYUNGSEOK wants to merge 1 commit into
TanStack:mainfrom
YESHYUNGSEOK:fix/partial-match-key-date
Open

fix(query-core): distinguish query keys differing only by a Date in partialMatchKey#10982
YESHYUNGSEOK wants to merge 1 commit into
TanStack:mainfrom
YESHYUNGSEOK:fix/partial-match-key-date

Conversation

@YESHYUNGSEOK

@YESHYUNGSEOK YESHYUNGSEOK commented Jun 25, 2026

Copy link
Copy Markdown

🎯 Changes

Non-exact query-key matching (partialMatchKey) traverses objects structurally via Object.keys(b).every(...). For values whose data lives in internal slots rather than own-enumerable keys, Object.keys() is [], so the comparison is vacuously true. This makes two keys that differ only by a Date compare as equal — even though hashKey serializes Dates to distinct ISO strings and therefore stores them as separate cache entries.

As a result, non-exact operations (invalidateQueries, refetchQueries, removeQueries, cancelQueries, and createPersister matching) over-match unrelated sibling queries:

useQuery({ queryKey: ['report', { from: new Date('2020-01-01') }], queryFn }) // entry A
useQuery({ queryKey: ['report', { from: new Date('2021-06-25') }], queryFn }) // entry B (distinct hash)

// intends to invalidate only A, but invalidates BOTH A and B:
queryClient.invalidateQueries({ queryKey: ['report', { from: new Date('2020-01-01') }] })

Fix

partialMatchKey now only traverses plain objects/arrays structurally; any other object (e.g. Date) is compared the same way hashKey serializes it, keeping non-exact matching consistent with cache identity:

  • Date keys that differ are no longer matched (the bug).
  • Map/Set/RegExp keep matching, because hashKey also serializes them to {} — they already share a cache entry, so behavior there is unchanged and consistent.

Tests

Added regression tests to the partialMatchKey suite: distinct Date values must not match, equal Date values must match, and Map keys that hash equally keep matching.

✅ Checklist

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

Verified locally on @tanstack/query-core: vitest run → 24 files / 548 tests pass, no type errors; eslint ./src → no new warnings on changed files. The full test:pr nx pipeline was not run.

🚀 Release Impact

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

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved non-exact query key matching so keys with different Date values no longer incorrectly match.
    • Kept matching consistent for non-plain objects, including cases like Map, when their serialized values are the same.
    • Added test coverage for Date and other hash-equivalent object matching behavior.

…artialMatchKey

Non-exact key matching traversed objects structurally, so two query keys
differing only by a `Date` value (e.g. `['report', { from: dateA }]` vs
`['report', { from: dateB }]`) were treated as equal even though `hashKey`
stores them as separate queries. This caused `invalidateQueries`,
`refetchQueries`, `removeQueries`, and `cancelQueries` (which default to
non-exact matching) to match unrelated sibling queries.

`partialMatchKey` now compares non-plain objects the same way `hashKey`
serializes them, keeping non-exact matching consistent with cache identity.

Co-authored-by: Claude <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

partialMatchKey now uses recursive matching only for plain arrays and plain objects, and hash-based comparison for other object values. New tests cover differing and equal Date values plus hash-equivalent Map values. A changeset records the query-core fix.

Changes

partialMatchKey matching update

Layer / File(s) Summary
Hash fallback for non-plain objects
packages/query-core/src/utils.ts, packages/query-core/src/__tests__/utils.test.tsx, .changeset/spicy-dates-match.md
partialMatchKey now recurses only through plain arrays and plain objects, falls back to hashKey for other objects, and adds Date and Map test coverage with a changeset entry.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

A bunny tapped the query tree,
For Dates and Maps, “match fair,” said he.
He twitched his nose, then gave a hop,
“Hash on the odd ones, recursive on the plop!”
🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately describes the main change to partialMatchKey handling for Date-based query keys.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The PR description follows the required template and includes the change summary, checklist, and release impact details.

✏️ 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.

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.

1 participant