{"record":{"id":"2b4daf303e8b9eb4","repo":"react/react","slug":"can-t-unmount-a-filtered-suspensenode-this-is-a-b","errorCode":null,"errorMessage":"Can't unmount a filtered SuspenseNode. This is a bug.","messagePattern":"Can't unmount a filtered SuspenseNode\\. This is a bug\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/react-devtools-shared/src/backend/fiber/renderer.js","lineNumber":2154,"sourceCode":"    suspenseNode.environments.forEach((count, env) => {\n      getStringID(env);\n    });\n    pendingSuspenderChanges.add(fiberInstance.id);\n  }\n\n  function recordSuspenseUnmount(suspenseInstance: SuspenseNode): void {\n    // $FlowFixMe[constant-condition]\n    if (__DEBUG__) {\n      console.log(\n        'recordSuspenseUnmount()',\n        suspenseInstance,\n        reconcilingParentSuspenseNode,\n      );\n    }\n\n    const devtoolsInstance = suspenseInstance.instance;\n    if (devtoolsInstance.kind !== FIBER_INSTANCE) {\n      throw new Error(\"Can't unmount a filtered SuspenseNode. This is a bug.\");\n    }\n    const fiberInstance = devtoolsInstance;\n    const id = fiberInstance.id;\n\n    // To maintain child-first ordering,\n    // we'll push it into one of these queues,\n    // and later arrange them in the correct order.\n    pendingRealUnmountedSuspenseIDs.push(id);\n\n    pendingSuspenderChanges.delete(id);\n    idToSuspenseNodeMap.delete(id);\n  }\n\n  // Running state of the remaining children from the previous version of this parent that\n  // we haven't yet added back. This should be reset anytime we change parent.\n  // Any remaining ones at the end will be deleted.\n  let remainingReconcilingChildren: null | DevToolsInstance = null;\n  // The previously placed child.","sourceCodeStart":2136,"sourceCodeEnd":2172,"githubUrl":"https://github.com/react/react/blob/22e4f993c7ce9373c95aef093b003f84249e2045/packages/react-devtools-shared/src/backend/fiber/renderer.js#L2136-L2172","documentation":"Thrown in recordSuspenseUnmount when the SuspenseNode's instance kind is not FIBER_INSTANCE (i.e. it is FILTERED_FIBER_INSTANCE or another variant). The unmount path for suspense nodes expects a real, unfiltered FiberInstance because it needs the numeric ID to queue for the removal operation batch. A filtered instance should have been handled differently (or not have a suspense node being unmounted at all).","triggerScenarios":"recordSuspenseUnmount receives a SuspenseNode whose .instance.kind !== FIBER_INSTANCE. This happens when the unmount traversal encounters a suspense node that was created for a filtered fiber but is being processed through the real-unmount queue.","commonSituations":"Active component filters during Suspense boundary teardown; fast-refresh re-mounting of filtered Suspense components; DevTools version mismatch affecting instance-kind bookkeeping.","solutions":["Clear component filters and retry.","Update React DevTools to the latest version.","If developing DevTools, check that the unmount dispatch routes filtered suspense nodes through the correct (non-throwing) path."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before calling recordSuspenseUnmount, verify instance kind\nif (suspenseInstance.instance.kind === FIBER_INSTANCE) {\n  recordSuspenseUnmount(suspenseInstance);\n}","typeGuard":"function isUnmountableSuspenseNode(node: SuspenseNode): boolean {\n  return node.instance.kind === FIBER_INSTANCE;\n}","tryCatchPattern":null,"preventionTips":["Avoid changing component filters during Suspense boundary teardown.","When developing DevTools, route filtered suspense nodes through a non-throwing unmount path.","Keep DevTools updated to benefit from filter/unmount interaction fixes."],"tags":["devtools-internal","suspense","filtering","unmount"],"backgroundTag":null,"analyzedSha":"22e4f993c7ce9373c95aef093b003f84249e2045","analyzedAt":"2026-08-12T22:33:25.580Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}