TanStack/query · error
No QueryClient found
Error message
No QueryClient found
What it means
Thrown by Angular's `injectDevtoolsPanel` inside its render effect when neither `devtoolsOptions().client` nor the Angular-DI-injected `QueryClient` is present. The devtools panel needs a live `QueryClient` instance to wire up `TanstackQueryDevtoolsPanel`, so it refuses to mount without one. It runs inside `untracked`, so the error propagates as an uncaught effect error during change detection.
Source
Thrown at packages/angular-query-experimental/src/devtools-panel/inject-devtools-panel.ts:69
}
if (!isBrowser)
return {
destroy,
}
effect(() => {
const {
client = injectedClient,
errorTypes = [],
styleNonce,
shadowDOMTarget,
onClose,
hostElement,
} = queryOptions()
untracked(() => {
if (!client) throw new Error('No QueryClient found')
if (!devtools && hostElement) {
import('@tanstack/query-devtools')
.then((queryDevtools) => {
devtools = new queryDevtools.TanstackQueryDevtoolsPanel({
client,
queryFlavor: 'Angular Query',
version: '5',
buttonPosition: 'bottom-left',
position: 'bottom',
initialIsOpen: true,
errorTypes,
styleNonce,
shadowDOMTarget,
onClose,
onlineManager,
})
devtools.mount(hostElement.nativeElement)
})View on GitHub (pinned to 159982c80b)
Solutions
- Register the QueryClient via `provideTanStackQuery(new QueryClient(), withDevtools(...))` (or `provideQueryClient(new QueryClient())`) in the same injector that hosts the component calling `injectDevtoolsPanel`.
- Pass the client explicitly in the options callback: `injectDevtoolsPanel(() => ({ client: myClient, hostElement: ref, ... }))`.
- Verify with the Angular devtools that the `QueryClient` token resolves at the component's injector by injecting it (optional) and logging before invoking the panel.
- If using a standalone component loaded through `loadComponent`, ensure the route or shell `ApplicationConfig.providers` includes the QueryClient provider.
Example fix
// before providers: [provideRouter(routes)] // after providers: [provideTanStackQuery(new QueryClient()), provideRouter(routes)]
Defensive patterns
Strategy: validation
Validate before calling
// Before mounting the panel, ensure a client resolves.
import { inject, Injector } from '@angular/core'
import { QueryClient } from '@tanstack/query-core'
function assertQueryClientAvailable(injector: Injector): QueryClient {
const client = injector.get(QueryClient, null)
if (!client) {
throw new Error('injectDevtoolsPanel: provide a QueryClient via provideTanStackQuery or pass client in options.')
}
return client
} Type guard
import { QueryClient } from '@tanstack/query-core'
const isQueryClient = (v: unknown): v is QueryClient =>
!!v && typeof (v as QueryClient).getQueryCache === 'function' && typeof (v as QueryClient).defaultQueryOptions === 'function' Try / catch
// Wrap the effect body so a missing client logs instead of crashing change detection.
try {
if (!client) throw new Error('No QueryClient found')
// ...mount devtools
} catch (err) {
console.error('[devtools-panel] skipped:', (err as Error).message)
} Prevention
- Always pair `withDevtools`/`injectDevtoolsPanel` with `provideTanStackQuery(new QueryClient(), ...)`.
- In tests, provide a stub QueryClient in the testing module config.
- For lazy-loaded components, ensure the route providers include the QueryClient.
- Pass the client explicitly in the options callback as a safety net.
When it happens
Trigger: Calling `injectDevtoolsPanel(...)` in a component that is not under a tree where `provideTanStackQuery(new QueryClient(), ...)` (or an explicit `QueryClient` provider) is registered, AND the options callback does not pass `client: myClient`. Also occurs when the panel options function returns no `client` and the `inject(QueryClient, { optional: true })` at line 43 resolves to `null`.
Common situations: Forgetting `provideTanStackQuery` in `appConfig.providers`; lazy-loading a standalone component into an injector that lacks the `QueryClient` provider; providing the client only in a child injector while `injectDevtoolsPanel` runs in a parent; SSR where DI wiring differs; providing the client after the panel effect already ran.
Related errors
- No QueryClient found
- No QueryClient was found in Svelte context. Did you forget t
- No 'queryClient' found in Vue context, use 'VueQueryPlugin'
- No QueryClient set, use QueryClientProvider to set one
- Expected enabled to be a boolean or a callback that returns
AI-assisted analysis of TanStack/query@159982c80b (2026-08-12).
Data as JSON: /api/errors/e96f4468d5256f85.
Report an issue: GitHub.