{"record":{"id":"5e12098848744571","repo":"TanStack/query","slug":"vue-query-hooks-can-only-be-used-inside-setup-fu","errorCode":null,"errorMessage":"vue-query hooks can only be used inside setup() function or functions that support injection context.","messagePattern":"vue-query hooks can only be used inside setup\\(\\) function or functions that support injection context\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/vue-query/src/useQueryClient.ts","lineNumber":9,"sourceCode":"import { hasInjectionContext, inject } from 'vue-demi'\n\nimport { getClientKey } from './utils'\nimport type { QueryClient } from './queryClient'\n\nexport function useQueryClient(id = ''): QueryClient {\n  // ensures that `inject()` can be used\n  if (!hasInjectionContext()) {\n    throw new Error(\n      'vue-query hooks can only be used inside setup() function or functions that support injection context.',\n    )\n  }\n\n  const key = getClientKey(id)\n  const queryClient = inject<QueryClient>(key)\n\n  if (!queryClient) {\n    throw new Error(\n      \"No 'queryClient' found in Vue context, use 'VueQueryPlugin' to properly initialize the library.\",\n    )\n  }\n\n  return queryClient\n}\n","sourceCodeStart":1,"sourceCodeEnd":25,"githubUrl":"https://github.com/TanStack/query/blob/159982c80b844487054155c38ffc760fe4208daf/packages/vue-query/src/useQueryClient.ts#L1-L25","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nexport function useTodos() {\n  fetch('/x').then(() => { const qc = useQueryClient(); qc.invalidateQueries(...) })\n}\n// after\nexport function useTodos() {\n  const qc = useQueryClient()\n  fetch('/x').then(() => qc.invalidateQueries(...))\n}","handlingStrategy":"validation","validationCode":"import { hasInjectionContext } from 'vue-demi'\nfunction ensureInjectionContext() {\n  if (!hasInjectionContext()) throw new Error('Call this hook from setup() only.')\n}","typeGuard":"import { getCurrentInstance } from 'vue-demi'\nconst isInSetup = (): boolean => !!getCurrentInstance()","tryCatchPattern":null,"preventionTips":["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."],"tags":["vue","setup","injection-context","lifecycle","configuration"],"backgroundTag":null,"analyzedSha":"159982c80b844487054155c38ffc760fe4208daf","analyzedAt":"2026-08-12T16:21:52.822Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}