-
-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Description
Describe the bug
The documentation for queryClient.invalidateQueries()
states that the type
parameter defaults to 'all'
, which should invalidate and refetch all matching queries (both active and inactive). However, the actual behavior only refetches active queries by default, leaving inactive cached queries stale.
Your minimal, reproducible example
https://codesandbox.io/p/sandbox/wpgfzw
Steps to reproduce
- Create queries with the same prefix (e.g.,
['todos']
,['todos', 1]
,['todos', 2]
) - Prefetch an additional query to create an inactive cached query (e.g.,
['todos', 3]
) - Call
queryClient.invalidateQueries({ queryKey: ['todos'] })
- Observe that only active queries refetch, while inactive cached queries remain stale
Expected behavior
According to the documentation, queryClient.invalidateQueries({ queryKey: ['todos'] })
should:
- Invalidate ALL queries with keys starting with
['todos']
- Refetch ALL matching queries (both active and inactive)
Actual behavior
queryClient.invalidateQueries({ queryKey: ['todos'] })
only:
- Refetches queries that have active observers (components using them)
- Leaves inactive cached queries (like prefetched queries) stale
How often does this bug happen?
None
Screenshots or Videos
No response
Platform
- OS: macOS/Windows/Linux
- Browser: Chrome/Firefox/Safari (any)
- Version of TanStack Query: 5.84.1
- React version: 18.0.0+
Tanstack Query adapter
None
TanStack Query version
5.84.1
TypeScript version
No response
Additional context
Root cause analysis:
The issue appears to be in the invalidation logic where the default refetch behavior uses 'active'
instead of 'all'
despite documentation claiming otherwise.
Workaround:
Explicitly specify type: 'all'
to get the documented behavior:
queryClient.invalidateQueries({ queryKey: ['todos'], type: 'all' })
Impact:
This discrepancy can cause subtle bugs where developers expect all cached data to be refreshed after mutations, but inactive cached queries remain stale, potentially leading to inconsistent application state.
Documentation references:
- The documentation states that
type
defaults to'all'
- However, the actual implementation appears to default to
'active'
behavior
Steps to Reproduce (Detailed)
### Detailed Reproduction Steps
1. **Setup queries with staleTime: Infinity**
```javascript
const queryClient = new QueryClient({
defaultOptions: {
queries: { staleTime: Infinity }
}
});
-
Create multiple queries with same prefix
// Active queries useQuery({ queryKey: ['todos'], queryFn: fetchTodos }); useQuery({ queryKey: ['todos', 1], queryFn: () => fetchTodosPage(1) }); // Inactive cached query (prefetched) queryClient.prefetchQuery({ queryKey: ['todos', 3], queryFn: () => fetchTodosPage(3) });
-
Test invalidation behavior
// This should refetch ALL queries according to docs queryClient.invalidateQueries({ queryKey: ['todos'] });
-
Observe the results
- ✅ Active queries: Get new fetch timestamps
- ❌ Inactive cached queries: Keep old fetch timestamps
-
Test workaround
// This works as expected queryClient.invalidateQueries({ queryKey: ['todos'], type: 'all' });
-
Verify fix
- ✅ Active queries: Get new fetch timestamps
- ✅ Inactive cached queries: Also get new fetch timestamps
Suggested Fix
Suggested Solution
Option 1: Fix Documentation
Update documentation to clarify that the default behavior only refetches active queries, and type: 'all'
is required for all queries.
Option 2: Fix Implementation
Change the default behavior to match documentation by making type: 'all'
the actual default.
Option 3: Breaking Change Warning
If changing the default behavior, consider it a breaking change and document the migration path.
Preference: Option 1 (documentation fix) would be safest for existing applications, but Option 2 (implementation fix) would match user expectations better.