TanStack/query · error
vue-query hooks can only be used inside setup() function or
Error message
vue-query hooks can only be used inside setup() function or functions that support injection context.
What it means
Thrown by `useQueryClient` in vue-query when Vue's `hasInjectionContext()` returns false. Vue only permits `inject()` during `setup()` (or functions called synchronously from it, or with explicit `bind`/`inject` scope). Calling the hook outside that boundary would crash on `inject()` anyway, so vue-query preempts with a clearer message.
Source
Thrown at packages/vue-query/src/useQueryClient.ts:9
import { hasInjectionContext, inject } from 'vue-demi'
import { getClientKey } from './utils'
import type { QueryClient } from './queryClient'
export function useQueryClient(id = ''): QueryClient {
// ensures that `inject()` can be used
if (!hasInjectionContext()) {
throw new Error(
'vue-query hooks can only be used inside setup() function or functions that support injection context.',
)
}
const key = getClientKey(id)
const queryClient = inject<QueryClient>(key)
if (!queryClient) {
throw new Error(
"No 'queryClient' found in Vue context, use 'VueQueryPlugin' to properly initialize the library.",
)
}
return queryClient
}
View on GitHub (pinned to 159982c80b)
Solutions
- Move the `useQueryClient()` call to the top of `setup()` before any `await`.
- Capture the client once in setup and pass it into async callbacks instead of re-calling the hook.
- If you must use it outside setup, capture it during setup and pass it explicitly: `const qc = useQueryClient(); later(qc)`.
- Use Vue's `effectScope`/`getCurrentInstance()` patterns only if you understand injection propagation.
Example fix
// before
export function useTodos() {
fetch('/x').then(() => { const qc = useQueryClient(); qc.invalidateQueries(...) })
}
// after
export function useTodos() {
const qc = useQueryClient()
fetch('/x').then(() => qc.invalidateQueries(...))
} Defensive patterns
Strategy: validation
Validate before calling
import { hasInjectionContext } from 'vue-demi'
function ensureInjectionContext() {
if (!hasInjectionContext()) throw new Error('Call this hook from setup() only.')
} Type guard
import { getCurrentInstance } from 'vue-demi'
const isInSetup = (): boolean => !!getCurrentInstance() Prevention
- Call `useQueryClient()` synchronously at the top of `setup()` before any `await`.
- Capture the client once and pass it into async callbacks.
- Never invoke vue-query hooks from event handlers detached from setup.
- For composables, ensure they are themselves called from setup.
When it happens
Trigger: Calling `useQueryClient()` (or any vue-query hook) outside `setup()` — e.g. in a top-level module statement, an async callback after `await`, a Vuex/Pinia action, a utility function not invoked from setup, or an event handler detached from the component instance.
Common situations: Refactoring to call hooks from composables that lost setup context; awaiting before calling the hook (the post-await continuation is no longer in injection context unless wrapped); SSR entry that invokes hooks eagerly; Pinia store actions using vue-query.
Related errors
- No 'queryClient' found in Vue context, use 'VueQueryPlugin'
- No QueryClient found
- No QueryClient found
- Expected enabled to be a boolean or a callback that returns
- No QueryClient was found in Svelte context. Did you forget t
AI-assisted analysis of TanStack/query@159982c80b (2026-08-12).
Data as JSON: /api/errors/5e12098848744571.
Report an issue: GitHub.