{"record":{"id":"dbf5e043d836421f","repo":"facebook/react","slug":"327","errorCode":"327","errorMessage":"Should not already be working.","messagePattern":"Should not already be working\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/react-reconciler/src/ReactFiberWorkLoop.js","lineNumber":1143,"sourceCode":"  const current = root.current;\n  current.lanes = lane;\n  markRootUpdated(root, lane);\n  ensureRootIsScheduled(root);\n}\n\nexport function isUnsafeClassRenderPhaseUpdate(fiber: Fiber): boolean {\n  // Check if this is a render phase update. Only called by class components,\n  // which special (deprecated) behavior for UNSAFE_componentWillReceive props.\n  return (executionContext & RenderContext) !== NoContext;\n}\n\nexport function performWorkOnRoot(\n  root: FiberRoot,\n  lanes: Lanes,\n  forceSync: boolean,\n): void {\n  if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {\n    throw new Error('Should not already be working.');\n  }\n\n  if (enableProfilerTimer && enableComponentPerformanceTrack) {\n    if (workInProgressRootRenderLanes !== NoLanes && workInProgress !== null) {\n      const yieldedFiber = workInProgress;\n      // We've returned from yielding to the event loop. Let's log the time it took.\n      const yieldEndTime = now();\n      switch (yieldReason) {\n        case SuspendedOnImmediate:\n        case SuspendedOnData:\n          logSuspendedYieldTime(yieldStartTime, yieldEndTime, yieldedFiber);\n          break;\n        case SuspendedOnAction:\n          logActionYieldTime(yieldStartTime, yieldEndTime, yieldedFiber);\n          break;\n        default:\n          logYieldTime(yieldStartTime, yieldEndTime);\n      }","sourceCodeStart":1125,"sourceCodeEnd":1161,"githubUrl":"https://github.com/facebook/react/blob/eafeac097ba51e1eab809c07102126bd5f8e5425/packages/react-reconciler/src/ReactFiberWorkLoop.js#L1125-L1161","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nfunction Row({row}) {\n  // render-phase flushSync re-enters the work loop\n  if (row.needsFocus) flushSync(() => setFocused(row.id));\n  return <div>{row.id}</div>;\n}\n\n// after\nfunction Row({row}) {\n  useEffect(() => {\n    if (row.needsFocus) setFocused(row.id); // scheduled, not re-entrant\n  }, [row.id]);\n  return <div>{row.id}</div>;\n}","handlingStrategy":"try-catch","validationCode":"import * as React from 'react';\nimport * as ReactDOM from 'react-dom/client';\nif (React.version !== ReactDOM.version) {\n  throw new Error(`react ${React.version} != react-dom ${ReactDOM.version}`);\n}","typeGuard":null,"tryCatchPattern":"// last-resort boundary so an internal invariant surfaces instead of white-screening silently\nclass InvariantBoundary extends React.Component {\n  state = {error: null};\n  static getDerivedStateFromError(error) { return {error}; }\n  componentDidCatch(error, info) { reportToTracker({error, info, reactVersion: React.version}); }\n  render() { return this.state.error ? <CrashScreen error={this.state.error} /> : this.props.children; }\n}","preventionTips":["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"],"tags":["internal-invariant","flush-sync","reentrancy","version-mismatch"],"backgroundTag":"react-internal-invariant","analyzedSha":"eafeac097ba51e1eab809c07102126bd5f8e5425","analyzedAt":"2026-08-21T22:01:08.818Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}