{"record":{"id":"80aa18bf0108e2e8","repo":"facebook/react","slug":"there-should-always-be-a-suspensenode-parent-on-a","errorCode":null,"errorMessage":"There should always be a SuspenseNode parent on a mounted instance.","messagePattern":"There should always be a SuspenseNode parent on a mounted instance\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/react-devtools-shared/src/backend/fiber/renderer.js","lineNumber":5295,"sourceCode":"        const owner = getUnfilteredOwner(fiber);\n        if (owner != null) {\n          if (typeof owner.tag === 'number') {\n            return getDisplayNameForFiber(owner as any);\n          } else {\n            return owner.name || '';\n          }\n        }\n      }\n      return getDisplayNameForFiber(fiber);\n    } else {\n      return devtoolsInstance.data.name || '';\n    }\n  }\n\n  function getNearestSuspenseNode(instance: DevToolsInstance): SuspenseNode {\n    while (instance.suspenseNode === null) {\n      if (instance.parent === null) {\n        throw new Error(\n          'There should always be a SuspenseNode parent on a mounted instance.',\n        );\n      }\n      instance = instance.parent;\n    }\n    return instance.suspenseNode;\n  }\n\n  function getNearestMountedDOMNode(publicInstance: Element): null | Element {\n    let domNode: null | Element = publicInstance;\n    while (domNode && !publicInstanceToDevToolsInstanceMap.has(domNode)) {\n      // $FlowFixMe[incompatible-type]: In practice this is either null or Element.\n      domNode = domNode.parentNode;\n    }\n    return domNode;\n  }\n\n  function getElementIDForHostInstance(","sourceCodeStart":5277,"sourceCodeEnd":5313,"githubUrl":"https://github.com/facebook/react/blob/eafeac097ba51e1eab809c07102126bd5f8e5425/packages/react-devtools-shared/src/backend/fiber/renderer.js#L5277-L5313","documentation":"Helper invariant used by the DevTools highlighter/inspector: getNearestSuspenseNode walks up the instance chain expecting to find an ancestor carrying a SuspenseNode. Hitting the root (parent null) without one means the caller asked for the nearest Suspense boundary of an instance whose subtree was never tracked as being inside any Suspense boundary.","triggerScenarios":"Highlighting/measuring an element whose ancestors include no Suspense boundary (or whose boundaries were skipped as filtered/unmounted) through a code path that assumes one exists; state desync when a SuspenseNode was popped but the instance still references the lookup path.","commonSituations":"Element highlighting or inspection on non-Suspense subtrees after version mismatches or earlier traversal failures in react-devtools-shared; embedded DevTools (React Native DevTools) on backend/renderer skew.","solutions":["Update React DevTools / react-devtools-shared to the build matching your renderer","Reload with DevTools attached to rebuild suspense tracking","Report the highlight/inspect action plus tree shape (any Suspense ancestors) as a repro","If you embed the backend, replace this lookup with a null-returning variant for non-Suspense paths"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":"// null-safe variant for embedded backends: walk ancestors, return null instead of throwing\nfunction findNearestSuspenseNode(instance: DevToolsInstance): SuspenseNode | null {\n  let cur = instance;\n  while (cur !== null) {\n    if (cur.suspenseNode !== null) return cur.suspenseNode;\n    cur = cur.parent;\n  }\n  return null; // caller skips suspense-scoped work instead of crashing\n}","tryCatchPattern":"try {\n  return getNearestSuspenseNode(instance);\n} catch (e) {\n  if (/SuspenseNode parent on a mounted instance/.test(e.message)) {\n    return null; // not inside any tracked Suspense boundary - skip\n  }\n  throw e;\n}","preventionTips":["Match DevTools/backend to the renderer version before using highlight/inspect features","Rebuild suspense tracking by reloading after traversal errors","When embedding the backend, prefer null-returning lookups over throwing invariants for optional boundaries","Report highlight actions on non-Suspense subtrees that trigger the error"],"tags":["react-devtools","invariant","suspense","highlight","lookup","internal"],"backgroundTag":"suspense-boundary-invariant-violation","analyzedSha":"eafeac097ba51e1eab809c07102126bd5f8e5425","analyzedAt":"2026-08-21T22:01:08.818Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}