{"record":{"id":"6afc6b6f1647ff53","repo":"TanStack/query","slug":"devtools-is-not-mounted","errorCode":null,"errorMessage":"Devtools is not mounted","messagePattern":"Devtools is not mounted","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/query-devtools/src/TanstackQueryDevtools.tsx","lineNumber":153,"sourceCode":"              return errors()\n            },\n            get hideDisabledQueries() {\n              return hideDisabledQueries()\n            },\n            get theme() {\n              return theme()\n            },\n          }}\n        />\n      )\n    }, el)\n    this.#isMounted = true\n    this.#dispose = dispose\n  }\n\n  unmount() {\n    if (!this.#isMounted) {\n      throw new Error('Devtools is not mounted')\n    }\n    this.#dispose?.()\n    this.#isMounted = false\n  }\n}\n\nexport { TanstackQueryDevtools }\n","sourceCodeStart":135,"sourceCodeEnd":161,"githubUrl":"https://github.com/TanStack/query/blob/159982c80b844487054155c38ffc760fe4208daf/packages/query-devtools/src/TanstackQueryDevtools.tsx#L135-L161","documentation":"Thrown by `TanstackQueryDevtools.unmount()` when `unmount` is called on an instance whose `#isMounted` flag is `false`. The class refuses to invoke the internal Solid `#dispose` handle when nothing is mounted because that handle would be `undefined`, and calling it would either no-op misleadingly or, after a future change, throw an unrelated TypeError. It fails fast to surface the lifecycle bug.","triggerScenarios":"Calling `devtools.unmount()` without a prior successful `mount()` on the same instance, or calling `unmount()` twice (the flag is reset to `false` after the first call). Frequent in effect cleanups that run on unmount of a component that never mounted the devtools, or in StrictMode where the dev cleanup fires for an effect whose dev mount was skipped/failed.","commonSituations":"React StrictMode double-invoking cleanups; conditionally-rendered devtools where the cleanup runs but the mount branch was not taken; calling `unmount` in a `disconnectCallback` / `willDestroy` hook of an element that was never connected; HMR re-running cleanup on a stale instance.","solutions":["Track mount state yourself and only unmount what you mounted: `useEffect(() => { devtools.mount(el); return () => { if (mounted) devtools.unmount() } })`.","Wrap the call: `try { devtools.unmount() } catch { /* not mounted, ignore */ }` when the lifecycle is outside your control.","Reproduce the lifecycle symmetrically — ensure every `mount()` path has exactly one matching `unmount()`.","Switch to the framework-specific devtools component (`<ReactQueryDevtools />`) which handles this internally."],"exampleFix":"// before - cleanup may run without a matching mount\nuseEffect(() => {\n  return () => devtools.unmount()\n}, [])\n\n// after - only unmount what we mounted\nuseEffect(() => {\n  let mounted = false\n  devtools.mount(el)\n  mounted = true\n  return () => { if (mounted) devtools.unmount() }\n}, [])","handlingStrategy":"validation","validationCode":"// Track mount state so unmount only runs when mounted\nlet mounted = false\nuseEffect(() => {\n  devtools.mount(el); mounted = true\n  return () => { if (mounted) { devtools.unmount(); mounted = false } }\n}, [])","typeGuard":"const isMounted = (d: { mount(el: HTMLElement): unknown; unmount(): void }) =>\n  Boolean((d as unknown as { _isMounted?: boolean })._isMounted)","tryCatchPattern":"try {\n  devtools.unmount()\n} catch (e) {\n  if (e.message === 'Devtools is not mounted') {\n    // no-op: nothing to clean up\n  } else throw e\n}","preventionTips":["Keep mount/unmount strictly symmetric: exactly one unmount per successful mount.","Track your own mounted flag when the lifecycle is outside your control (StrictMode, HMR).","Prefer <ReactQueryDevtools /> over the vanilla class to avoid manual lifecycle bookkeeping.","Never register a cleanup unmount without registering the matching mount in the same effect."],"tags":["devtools","unmount","lifecycle","solid","vanilla"],"backgroundTag":null,"analyzedSha":"159982c80b844487054155c38ffc760fe4208daf","analyzedAt":"2026-08-12T16:21:52.822Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}