facebook/react · error · Error
There should always be a SuspenseNode parent on a mounted in
Error message
There should always be a SuspenseNode parent on a mounted instance.
What it means
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.
Source
Thrown at packages/react-devtools-shared/src/backend/fiber/renderer.js:5295
const owner = getUnfilteredOwner(fiber);
if (owner != null) {
if (typeof owner.tag === 'number') {
return getDisplayNameForFiber(owner as any);
} else {
return owner.name || '';
}
}
}
return getDisplayNameForFiber(fiber);
} else {
return devtoolsInstance.data.name || '';
}
}
function getNearestSuspenseNode(instance: DevToolsInstance): SuspenseNode {
while (instance.suspenseNode === null) {
if (instance.parent === null) {
throw new Error(
'There should always be a SuspenseNode parent on a mounted instance.',
);
}
instance = instance.parent;
}
return instance.suspenseNode;
}
function getNearestMountedDOMNode(publicInstance: Element): null | Element {
let domNode: null | Element = publicInstance;
while (domNode && !publicInstanceToDevToolsInstanceMap.has(domNode)) {
// $FlowFixMe[incompatible-type]: In practice this is either null or Element.
domNode = domNode.parentNode;
}
return domNode;
}
function getElementIDForHostInstance(View on GitHub (pinned to eafeac097b)
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
Defensive patterns
Strategy: fallback
Type guard
// null-safe variant for embedded backends: walk ancestors, return null instead of throwing
function findNearestSuspenseNode(instance: DevToolsInstance): SuspenseNode | null {
let cur = instance;
while (cur !== null) {
if (cur.suspenseNode !== null) return cur.suspenseNode;
cur = cur.parent;
}
return null; // caller skips suspense-scoped work instead of crashing
} Try / catch
try {
return getNearestSuspenseNode(instance);
} catch (e) {
if (/SuspenseNode parent on a mounted instance/.test(e.message)) {
return null; // not inside any tracked Suspense boundary - skip
}
throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Attempted to measure a Suspense node that does not exist.
- The should not be any remaining suspense node children if th
- There should always be an Offscreen Fiber child in a hydrate
- A dehydrated Suspense node should not have a content Fiber.
- Encountered a dehydrated Suspense boundary that was previous
AI-assisted analysis of facebook/react@eafeac097b (2026-08-21).
Data as JSON: /api/errors/80aa18bf0108e2e8.
Report an issue: GitHub.