{"record":{"id":"0fa7f5f0bb662fc5","repo":"facebook/react","slug":"598","errorCode":"598","errorMessage":"Maximum update depth exceeded. This could be an infinite loop. This can happen when a component repeatedly calls setState during render phase or inside useLayoutEffect, causing infinite render loop. React limits the number of nested updates to prevent infinite loops.","messagePattern":"Maximum update depth exceeded\\. This could be an infinite loop\\. This can happen when a component repeatedly calls setState during render phase or inside useLayoutEffect, causing infinite render loop\\. React limits the number of nested updates to prevent infinite loops\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/react-reconciler/src/ReactFiberWorkLoop.js","lineNumber":5214,"sourceCode":"  }\n\n  retryTimedOutBoundary(boundaryFiber, retryLane);\n}\n\nfunction throwForcedInfiniteRenderLoopError(\n  root: FiberRoot | null,\n  renderLanes: Lanes,\n): empty {\n  if (root !== null) {\n    // Disable concurrent error recovery for the in-progress render so the thrown\n    // error reaches the nearest error boundary and breaks the infinite update\n    // loop instead of being silently retried by the recovery mechanism.\n    root.errorRecoveryDisabledLanes = mergeLanes(\n      root.errorRecoveryDisabledLanes,\n      renderLanes,\n    );\n  }\n  throw new Error(\n    'Maximum update depth exceeded. This could be an infinite loop. This can happen when a component ' +\n      'repeatedly calls setState during render phase or inside useLayoutEffect, ' +\n      'causing infinite render loop. React limits the number of nested updates to ' +\n      'prevent infinite loops.',\n  );\n}\n\nexport function throwIfInfiniteUpdateLoopDetected(\n  isFromInfiniteRenderLoopDetectionInstrumentation: boolean,\n) {\n  if (nestedUpdateCount > NESTED_UPDATE_LIMIT) {\n    nestedUpdateCount = 0;\n    nestedPassiveUpdateCount = 0;\n    rootWithNestedUpdates = null;\n    rootWithPassiveNestedUpdates = null;\n\n    const updateKind = nestedUpdateKind;\n    nestedUpdateKind = NO_NESTED_UPDATE;","sourceCodeStart":5196,"sourceCodeEnd":5232,"githubUrl":"https://github.com/facebook/react/blob/eafeac097ba51e1eab809c07102126bd5f8e5425/packages/react-reconciler/src/ReactFiberWorkLoop.js#L5196-L5232","documentation":"React counts nested updates per root and caps them at NESTED_UPDATE_LIMIT (50). When the infinite-render-loop instrumentation (enableInfiniteRenderLoopDetectionForceThrow) determines the newest update in the chain was scheduled from render phase or useLayoutEffect, throwForcedInfiniteRenderLoopError disables error-recovery lanes for that render (so the throw is not silently retried) and throws this variant naming render-phase setState and useLayoutEffect as the cause.","triggerScenarios":"More than 50 nested updates where the last update came from render phase or a layout effect: setState called unconditionally during render, or a useLayoutEffect that sets state after every commit without an equality guard or with missing dependencies, so each render schedules another render.","commonSituations":"Syncing props into state with an effect that always writes because of fresh object/array identity; 'adjusting state during render' done without an equality check; scroll/measure loops in useLayoutEffect; store subscriptions writing back on every notification.","solutions":["Derive the value during render instead of storing it, or guard the update: only setState when the value actually changed","If state must be set during render, follow React's documented pattern: set the same component's state and bail out when unchanged","Move non-layout synchronization from useLayoutEffect to useEffect with a correct dependency array","Lift the state to the closest common owner so one update replaces the ping-pong between components"],"exampleFix":"// before\nfunction List({items}) {\n  const [selected, setSelected] = useState([]);\n  useLayoutEffect(() => {\n    setSelected(items.map((i) => i.id)); // runs after every commit -> infinite loop\n  });\n  return <Rows selected={selected} items={items} />;\n}\n\n// after\nfunction List({items}) {\n  const selected = items.map((i) => i.id); // derived during render, no state\n  return <Rows selected={selected} items={items} />;\n}","handlingStrategy":"validation","validationCode":"// guard effect-driven updates so identical values bail out\nuseLayoutEffect(() => {\n  setViewport((prev) =>\n    prev.width === box.width && prev.height === box.height ? prev : box,\n  );\n}, [box]);","typeGuard":null,"tryCatchPattern":"// the throw is catchable by an error boundary (error recovery is disabled for these lanes)\nclass LoopBoundary extends React.Component {\n  state = {error: null};\n  static getDerivedStateFromError(error) { return {error}; }\n  componentDidCatch(error) {\n    if (error.message.includes('Maximum update depth exceeded')) {\n      logInfiniteLoop(this.props.name);\n    }\n  }\n  render() { return this.state.error ? null : this.props.children; }\n}","preventionTips":["Derive values during render instead of syncing them into state with effects","Give every setState-in-effect a real dependency array and an equality guard","When adjusting state during render, always return the previous state when nothing changed"],"tags":["infinite-loop","render-phase-update","use-layout-effect","set-state","nested-updates"],"backgroundTag":"maximum-update-depth-exceeded","analyzedSha":"eafeac097ba51e1eab809c07102126bd5f8e5425","analyzedAt":"2026-08-21T22:01:08.818Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}