Skip to content

feat(query-core): forward caller-provided meta into the invalidate action payload#10540

Open
maastrich wants to merge 1 commit intoTanStack:mainfrom
maastrich:feat/invalidate-queries-meta
Open

feat(query-core): forward caller-provided meta into the invalidate action payload#10540
maastrich wants to merge 1 commit intoTanStack:mainfrom
maastrich:feat/invalidate-queries-meta

Conversation

@maastrich
Copy link
Copy Markdown

@maastrich maastrich commented Apr 20, 2026

Summary

Implements the proposal from discussion #10539.

  • Adds meta?: QueryMeta to InvalidateOptions (second arg of invalidateQueries)
  • Threads it through query.invalidate(meta) into the dispatched InvalidateAction
  • Makes event.action.meta available in queryCache.subscribe for structured observability and echo-suppression

Usage

queryClient.invalidateQueries(
  { queryKey: ['orders'] },
  { meta: { source: 'websocket', traceId: 'abc123' } },
)

queryCache.subscribe((event) => {
  if (event.type === 'updated' && event.action.type === 'invalidate') {
    console.log(event.action.meta) // { source: 'websocket', traceId: 'abc123' }
  }
})

Notes

  • Fully additive — meta is optional and defaults to undefined. No existing call site is affected.
  • options.meta is distinct from filters.meta (which filters queries by their meta).
  • The existing isInvalidated guard is preserved: if a query is already invalidated, the dispatch is skipped and the meta from subsequent calls is silently dropped. This is consistent with current behavior and can be revisited separately.
  • query-broadcast-client-experimental does not broadcast invalidate actions today, so no changes are needed there.

Checklist

  • Core implementation (query.ts, queryClient.ts, types.ts)
  • Test in queryClient.test.tsx
  • Reference docs updated (docs/reference/QueryClient.md)
  • Guide updated (docs/framework/react/guides/query-invalidation.md) — other framework guides mirror it via ref:
  • Changeset (minor for @tanstack/query-core)

Closes discussion: #10539

Summary by CodeRabbit

Release Notes

  • New Features

    • Query invalidation now supports passing a meta option that is forwarded to cache subscriber events for observation.
  • Documentation

    • Added guide with code examples demonstrating how to pass metadata during invalidation and access it through cache subscribers.
  • Tests

    • Added tests verifying metadata is correctly forwarded through invalidation events.

…cache action

Adds an optional `meta` field to `InvalidateOptions` that flows through
to the `invalidate` action payload visible in `queryCache.subscribe`,
enabling structured observability and echo-suppression without
out-of-band bookkeeping.

Closes TanStack#10539 (discussion)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions github-actions bot added documentation Improvements or additions to documentation package: query-core labels Apr 20, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 20, 2026

📝 Walkthrough

Walkthrough

Adds support for passing meta options through queryClient.invalidateQueries(), which are forwarded to the internal invalidate action. This enables queryCache.subscribe() subscribers to access metadata about invalidation sources via event.action.meta. Changes include type updates, implementation in QueryClient and Query classes, tests, and documentation.

Changes

Cohort / File(s) Summary
Type System & Interfaces
packages/query-core/src/types.ts, packages/query-core/src/query.ts
Updated InvalidateOptions to extend RefetchOptions with optional meta?: QueryMeta field. Extended Query.invalidate() method signature to accept meta?: QueryMeta parameter and include it in the dispatched invalidate action.
Core Implementation
packages/query-core/src/queryClient.ts
Modified QueryClient.invalidateQueries() to pass options.meta to each matched query's invalidate() call.
Testing
packages/query-core/src/__tests__/queryClient.test.tsx
Added test case verifying that meta passed to invalidateQueries() is forwarded to queryCache subscribers via the invalidate action payload.
Documentation
.changeset/invalidate-queries-meta.md, docs/framework/react/guides/query-invalidation.md, docs/reference/QueryClient.md
Added changeset entry and documentation describing the new meta parameter in invalidateQueries(), including usage examples and clarification distinguishing this parameter-level meta from filter-level meta.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 Hop! The meta bounds through the query cache,
From invalidate down in a flash!
Subscribers perk up with knowing glee,
"Who cleared me?" they now can see!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: forwarding caller-provided meta into the invalidate action payload, matching the core implementation across query.ts, queryClient.ts, and types.ts.
Description check ✅ Passed The description comprehensively covers the changes, includes usage examples, provides detailed notes about behavior, and includes a completed checklist matching the repository template.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ 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 and usage tips.

Copy link
Copy Markdown
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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/query-core/src/queryClient.ts (1)

297-311: ⚠️ Potential issue | 🟠 Major

Strip meta before forwarding options to refetchQueries.

options.meta is intended for the invalidate action, but the full options object is also passed into refetchQueries. That leaks the same object into query.fetch(..., fetchOptions), where fetchOptions.meta is interpreted as fetch metadata and can update fetchMeta / fetch events with invalidation metadata.

Proposed fix
   ): Promise<void> {
     return notifyManager.batch(() => {
+      const { meta, ...refetchOptions } = options
+
       this.#queryCache.findAll(filters).forEach((query) => {
-        query.invalidate(options.meta)
+        query.invalidate(meta)
       })

       if (filters?.refetchType === 'none') {
         return Promise.resolve()
       }
@@
           ...filters,
           type: filters?.refetchType ?? filters?.type ?? 'active',
         },
-        options,
+        refetchOptions,
       )
     })
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/query-core/src/queryClient.ts` around lines 297 - 311, The
invalidate loop correctly uses options.meta but you must avoid forwarding that
same meta into refetchQueries; when calling this.refetchQueries(...) strip out
meta from the options passed (e.g., clone options then delete or omit
options.meta) so invalidate receives meta but the refetch call receives options
without meta; locate the call to notifyManager.batch ->
this.#queryCache.findAll(...).forEach(query => query.invalidate(options.meta))
and change the refetchQueries invocation to pass a copy of options with meta
removed before spreading into the second argument.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/query-core/src/queryClient.ts`:
- Around line 297-311: The invalidate loop correctly uses options.meta but you
must avoid forwarding that same meta into refetchQueries; when calling
this.refetchQueries(...) strip out meta from the options passed (e.g., clone
options then delete or omit options.meta) so invalidate receives meta but the
refetch call receives options without meta; locate the call to
notifyManager.batch -> this.#queryCache.findAll(...).forEach(query =>
query.invalidate(options.meta)) and change the refetchQueries invocation to pass
a copy of options with meta removed before spreading into the second argument.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6a2f6275-2903-4509-b84a-b2a7e73fffc8

📥 Commits

Reviewing files that changed from the base of the PR and between 646f04e and 848c49e.

📒 Files selected for processing (7)
  • .changeset/invalidate-queries-meta.md
  • docs/framework/react/guides/query-invalidation.md
  • docs/reference/QueryClient.md
  • packages/query-core/src/__tests__/queryClient.test.tsx
  • packages/query-core/src/query.ts
  • packages/query-core/src/queryClient.ts
  • packages/query-core/src/types.ts

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

Labels

documentation Improvements or additions to documentation package: query-core

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant