facebook/react · error · Error
There should always be an Offscreen Fiber child in a hydrate
Error message
There should always be an Offscreen Fiber child in a hydrated Suspense boundary.
What it means
DevTools backend invariant hit while mounting the mirrored tree: on modern React (where OffscreenComponent is a known tag), a SuspenseComponent fiber that is already hydrated must have a child fiber - the Offscreen wrapper that React puts around suspense content. A null fiber.child on a hydrated boundary breaks the traversal's structural assumption about React 19+ trees.
Source
Thrown at packages/react-devtools-shared/src/backend/fiber/renderer.js:3299
if (fiber.tag === SuspenseComponent || fiber.tag === HostRoot) {
newSuspenseNode = createSuspenseNode(newInstance);
// Measure this Suspense node. In general we shouldn't do this until we have
// inserted the new children but since we know this is a FiberInstance we'll
// just use the Fiber anyway.
// Fallbacks get attributed to the parent so we only measure if we're
// showing primary content.
if (fiber.tag === SuspenseComponent) {
if (OffscreenComponent === -1) {
const isTimedOut = fiber.memoizedState !== null;
if (!isTimedOut) {
newSuspenseNode.rects = measureInstance(newInstance);
}
} else {
const hydrated = isFiberHydrated(fiber);
if (hydrated) {
const contentFiber = fiber.child;
if (contentFiber === null) {
throw new Error(
'There should always be an Offscreen Fiber child in a hydrated Suspense boundary.',
);
}
} else {
// This Suspense Fiber is still dehydrated. It won't have any children
// until hydration.
}
const isTimedOut = fiber.memoizedState !== null;
if (!isTimedOut) {
newSuspenseNode.rects = measureInstance(newInstance);
}
}
} else {
newSuspenseNode.rects = measureInstance(newInstance);
}
recordSuspenseMount(newSuspenseNode, reconcilingParentSuspenseNode);
}
insertChild(newInstance);View on GitHub (pinned to eafeac097b)
Solutions
- Update React DevTools to the version aligned with your React release channel
- Let hydration finish before opening DevTools, or reload with DevTools already attached so the tree is captured post-hydration
- Report the boundary structure (Suspense nesting, Activity usage, hydration mode) as a repro to facebook/react
- If you control the build, verify only one copy of react-devtools-shared is loaded
Defensive patterns
Strategy: try-catch
Try / catch
try {
backend.handleCommitFiberRoot(renderer, root);
} catch (e) {
if (/Offscreen Fiber child in a hydrated Suspense boundary/.test(e.message)) {
reportDevToolsBug(e); // hydration-shape invariant: report, then reload backend
} else throw e;
} Prevention
- Match DevTools and React versions, especially across React 19 Offscreen/Activity changes
- Let hydration finish (or attach DevTools after load) before inspecting hydrated Suspense trees
- Report hydration + Suspense tree shapes that trigger it - the invariant encodes a React contract
- Reload the page to rebuild the mirror after any DevTools invariant error
When it happens
Trigger: DevTools mirroring an SSR-hydrated Suspense boundary whose content fiber is missing; DevTools attached during hydration; a React build that omits the Offscreen wrapper (older or non-standard renderer) paired with a DevTools backend that expects it.
Common situations: React 19 / canary with an outdated DevTools extension; hydration of Suspense boundaries (including Activity/Offscreen usage) while the Components tree is open; third-party renderers reusing react-devtools-shared with different child layouts.
Related errors
- A dehydrated Suspense node should not have a content Fiber.
- Encountered a dehydrated Suspense boundary that was previous
- The should not be any remaining suspense node children if th
- Attempted to measure a Suspense node that does not exist.
- There should always be a SuspenseNode parent on a mounted in
AI-assisted analysis of facebook/react@eafeac097b (2026-08-21).
Data as JSON: /api/errors/88f119d8169b2005.
Report an issue: GitHub.