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

  1. Register the QueryClient via `provideTanStackQuery(new QueryClient(), withDevtools(...))` (or `provideQueryClient(new QueryClient())`) in the same injector that hosts the component calling `injectDevtoolsPanel`.
  2. Pass the client explicitly in the options callback: `injectDevtoolsPanel(() => ({ client: myClient, hostElement: ref, ... }))`.
  3. 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.
  4. 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

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


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