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

  1. Reproduce on the latest stable React release and upgrade — many 'Root did not complete' reports are fixed regressions
  2. Remove third-party renderers, devtools hooks, or monkey-patches to isolate the cause
  3. 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

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


AI-assisted analysis of facebook/react@eafeac097b (2026-08-21). Data as JSON: /api/errors/8ac208fb3c6b6068. Report an issue: GitHub.