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

  1. Move the `useQueryClient()` call to the top of `setup()` before any `await`.
  2. Capture the client once in setup and pass it into async callbacks instead of re-calling the hook.
  3. If you must use it outside setup, capture it during setup and pass it explicitly: `const qc = useQueryClient(); later(qc)`.
  4. 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

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


AI-assisted analysis of TanStack/query@159982c80b (2026-08-12). Data as JSON: /api/errors/5e12098848744571. Report an issue: GitHub.