facebook/react · error
327
327
Error message
Should not already be working.
What it means
performWorkOnRoot is the entry point for performing sync work on a root; before touching the tree it asserts the reconciler is idle (executionContext free of RenderContext and CommitContext). Re-entering it while a render or commit is already in progress means work was scheduled re-entrantly from inside render/commit — either a misused synchronous API (flushSync-style flush at an illegal point) or a genuine reconciler bug (error code 327).
Source
Thrown at packages/react-reconciler/src/ReactFiberWorkLoop.js:1143
const current = root.current;
current.lanes = lane;
markRootUpdated(root, lane);
ensureRootIsScheduled(root);
}
export function isUnsafeClassRenderPhaseUpdate(fiber: Fiber): boolean {
// Check if this is a render phase update. Only called by class components,
// which special (deprecated) behavior for UNSAFE_componentWillReceive props.
return (executionContext & RenderContext) !== NoContext;
}
export function performWorkOnRoot(
root: FiberRoot,
lanes: Lanes,
forceSync: boolean,
): void {
if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {
throw new Error('Should not already be working.');
}
if (enableProfilerTimer && enableComponentPerformanceTrack) {
if (workInProgressRootRenderLanes !== NoLanes && workInProgress !== null) {
const yieldedFiber = workInProgress;
// We've returned from yielding to the event loop. Let's log the time it took.
const yieldEndTime = now();
switch (yieldReason) {
case SuspendedOnImmediate:
case SuspendedOnData:
logSuspendedYieldTime(yieldStartTime, yieldEndTime, yieldedFiber);
break;
case SuspendedOnAction:
logActionYieldTime(yieldStartTime, yieldEndTime, yieldedFiber);
break;
default:
logYieldTime(yieldStartTime, yieldEndTime);
}View on GitHub (pinned to eafeac097b)
Solutions
- Check for duplicate or mismatched react/react-dom copies (npm ls react react-dom) and dedupe them; both must be the same exact version
- Audit for flushSync (or renderer sync flush APIs) invoked during render or commit phases and move the call to an event handler or effect
- Upgrade react and react-dom together to the latest stable release
- If it persists on the latest stable release with one package copy, file a React issue with a minimal reproduction
Example fix
// before
function Row({row}) {
// render-phase flushSync re-enters the work loop
if (row.needsFocus) flushSync(() => setFocused(row.id));
return <div>{row.id}</div>;
}
// after
function Row({row}) {
useEffect(() => {
if (row.needsFocus) setFocused(row.id); // scheduled, not re-entrant
}, [row.id]);
return <div>{row.id}</div>;
} Defensive patterns
Strategy: try-catch
Validate before calling
import * as React from 'react';
import * as ReactDOM from 'react-dom/client';
if (React.version !== ReactDOM.version) {
throw new Error(`react ${React.version} != react-dom ${ReactDOM.version}`);
} Try / catch
// last-resort boundary so an internal invariant surfaces instead of white-screening silently
class InvariantBoundary extends React.Component {
state = {error: null};
static getDerivedStateFromError(error) { return {error}; }
componentDidCatch(error, info) { reportToTracker({error, info, reactVersion: React.version}); }
render() { return this.state.error ? <CrashScreen error={this.state.error} /> : this.props.children; }
} Prevention
- Keep exactly one react and one react-dom copy in the bundle, at identical versions
- Never call flushSync during render or commit phases — schedule from handlers or effects
- Pin stable releases in production; canary builds carry higher invariant risk
When it happens
Trigger: A synchronous update being performed on a root while executionContext already includes RenderContext or CommitContext — e.g. a flushSync-like synchronous flush triggered from within a component render or a commit-phase code path on the legacy sync route.
Common situations: Two copies or mismatched versions of react and react-dom in one page (bundling, aliasing, dedupe failures) each running their own work loop; third-party renderers or devtools hooking the reconciler; canary/experimental regressions; genuine reconciler bugs filed as GitHub issues.
Related errors
- 331
- Invalid reference.
- Failed to read a RSC payload created by a development versio
- Expected overrideError() to not get called for earlier React
- Expected overrideSuspense() to not get called for earlier Re
AI-assisted analysis of facebook/react@eafeac097b (2026-08-21).
Data as JSON: /api/errors/dbf5e043d836421f.
Report an issue: GitHub.