facebook/react · error
345
345
Error message
Root did not complete. This is a bug in React.
What it means
finishConcurrentRender only accepts terminal exit statuses (the suspended variants, RootErrored, RootCompleted). Receiving RootInProgress or RootFatalErrored means the render pass ended without a usable finished tree — an invariant violation inside the reconciler (error code 345), not an error in application code. RootInProgress here implies the work loop exited while still marked in-progress; RootFatalErrored should have been handled before commit.
Source
Thrown at packages/react-reconciler/src/ReactFiberWorkLoop.js:1433
errors,
);
}
}
function finishConcurrentRender(
root: FiberRoot,
exitStatus: RootExitStatus,
finishedWork: Fiber,
lanes: Lanes,
renderEndTime: number, // Profiling-only
) {
// TODO: The fact that most of these branches are identical suggests that some
// of the exit statuses are not best modeled as exit statuses and should be
// tracked orthogonally.
switch (exitStatus) {
case RootInProgress:
case RootFatalErrored: {
throw new Error('Root did not complete. This is a bug in React.');
}
case RootSuspendedWithDelay: {
if (!includesOnlyTransitions(lanes) && !includesOnlyRetries(lanes)) {
// Commit the placeholder.
break;
}
}
// Fallthrough
case RootSuspendedAtTheShell: {
// This is a transition, so we should exit without committing a
// placeholder and without scheduling a timeout. Delay indefinitely
// until we receive more data.
if (enableProfilerTimer && enableComponentPerformanceTrack) {
setCurrentTrackFromLanes(lanes);
logSuspendedRenderPhase(
renderStartTime,
renderEndTime,
lanes,View on GitHub (pinned to eafeac097b)
Solutions
- Reproduce on the latest stable React release and upgrade — many 'Root did not complete' reports are fixed regressions
- Remove third-party renderers, devtools hooks, or monkey-patches to isolate the cause
- Reduce to a minimal repro (often an interruption + update race) and file a React issue with the version and stack
Defensive patterns
Strategy: try-catch
Try / catch
// wrap the app so render invariants are reported with version context
componentDidCatch(error, info) {
if (/Root did not complete/.test(error.message)) {
report({kind: 'react-invariant', error, info, version: React.version});
}
} Prevention
- Run the latest stable React — exit-status invariants have had multiple fixed regressions
- Remove renderer forks and reconciler monkey-patches before debugging further
- Keep a minimal repro ready when filing the upstream issue
When it happens
Trigger: The work loop returns with the root status still RootInProgress, or a fatally errored root is handed to the commit path — states that renderRootSync/finishConcurrentRender bookkeeping should have converted earlier.
Common situations: Canary/experimental regressions; races between sync and concurrent updates on the same root (several such bugs were fixed historically); third-party instrumentation or renderer forks interfering with exit-status bookkeeping.
Related errors
- 329
- 177
- Expected to see a frame at the next depth.
- Expected root pseudo key to be known.
- Expected counter to be known.
AI-assisted analysis of facebook/react@eafeac097b (2026-08-21).
Data as JSON: /api/errors/8ac208fb3c6b6068.
Report an issue: GitHub.