Maximum update depth exceeded
Filed under Next.js & React errors
A setState call is triggering itself: it runs during render, or in an effect that re-runs because of the very state it sets, so React renders, updates, renders, updates — forever.
Fastest route
Give your AI this prompt
Copy it, replace the bracketed part with your error, and send it.
Preview the prompt
My React app crashes with: "Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but it must be guarded by a condition, or wrapped in an event handler." Here is the component named in the error: [paste the component, including its useEffect calls and where its props come from]. Please: 1) find the exact setState call that triggers itself — during render, in an effect with no dependency array, in an effect that depends on the state it sets, or via a dependency that is recreated every render, 2) name which of those shapes it is before changing code, 3) fix it by adding or correcting the dependency array, switching to the function form of setState (setX(prev => ...)) where the effect reads its own state, stabilizing recreated objects or functions with useMemo or useCallback, or moving the update into an event handler or effect — whichever matches the cause. Constraints: do not silence it by wrapping setState in a setTimeout, do not remove the state update the feature needs, and explain in one sentence why the loop happened.
Fix it yourself
Follow the repair
- Open the component the error names and find every setState it can reach. Search the file for the setter calls (setSomething) and note where each one lives: component body, effect, or event handler. Handlers are innocent — they wait for a human. Body and effect calls are your suspects, and one of them is triggering itself.
- If a setState sits in the component body, condition it or move it. A body-level update is only legal when it terminates — React's own pattern for adjusting state during render compares against the previous value:
If the update is not really "adjust state while rendering," it belongs in an event handler or an effect instead — move it and the loop dies.// Loop: runs on every render, forever setItems(sorted); // Terminating: only updates when the value actually changed if (items !== sorted) { setItems(sorted); } - If the suspect is an effect with no dependency array, add the array. This is the single most common version of the bug:
List in the array the values the effect genuinely reads — and if the effect reads the state it sets, use the function form (setCount(c => c + 1)) so the state does not need to be a dependency at all.// Loop: no array means "run after every render" useEffect(() => { setCount(count + 1); }); // Fixed: runs once on mount useEffect(() => { setCount(c => c + 1); }, []); - Check the array for self-dependence and unstable values. Two quieter traps: the effect's dependency list contains the state the effect itself sets, so each update refires it — restructure so the effect depends on the source data, not its own output. And a dependency written inline —
useEffect(fn, [{ mode: "auto" }])or a function defined in the component body — is a brand-new value every render, so the effect refires constantly. Move that value inside the effect, hoist it outside the component, or wrap it in useMemo / useCallback. - Check for a child updating a parent during render. If the console also warns "Cannot update a component while rendering a different component," a child is calling a parent's setter mid-render — often disguised as syncing: the child receives data and immediately reports a processed version upward. Move that call into the child's useEffect, or better, compute the value in the parent so there is nothing to sync.
- Re-test by watching the render count, not just the error. The error disappearing means React stopped counting, not necessarily that the loop is gone — a slower loop can hum underneath. Temporarily log in the component body, load the page, and confirm renders settle after a couple of passes instead of climbing endlessly. Then remove the log.
Why this happensOptional explanation
React renders a component, and if anything during that process asks for a state update, React renders again. That is normal — it is how the whole system works. This error appears when the chain never terminates: render causes update, update causes render, and each pass through the loop looks identical to the last. React counts the nested updates, and at the limit it throws "Maximum update depth exceeded" and stops, rather than letting the loop consume the browser.
So the error is never really about depth. It is a loop report. In function components the loop almost always lives in one of three places: a setState call sitting directly in the render body, a useEffect that runs after every render because it has no dependency array, or a useEffect whose dependency is recreated — a fresh object, array, or function — on every single render, so the array changes every time even though you wrote one. A fourth variant crosses components: a child invoking a parent's setState while the child renders, which React flags with a companion warning about updating one component while rendering another.
- setState in the render body: an update called unconditionally while the component renders — every render schedules the next.
- Effect with no dependency array: runs after every render; if it sets state, the loop is automatic.
- Effect depends on what it sets: the state you update is in your own dependency array, so every update refires the effect.
- Unstable dependency: an inline object, array, or function literal is a new value every render, so the effect refires every render despite the array.
- Cross-component update: a child calling a parent's setState during the child's render.
Quick answers
What is Minified React error #185? Is it the same thing?
In production builds React minifies its error messages to save space, and #185 is the maximum-update-depth error wearing a number. The console message includes a link that decodes it — but if your app froze in an update loop, it is this error nine times out of ten.
I get "Too many re-renders" instead. Same problem?
No — that is a sibling error with a near-identical name, caused by calling setState directly in the component body during render, unconditionally. Same family (a setState that retriggers itself), different location: render body instead of effect. Both are fixed by moving or conditioning the update.
What if the effect really does need to react to every change?
The snapshot trick: a variable outside the component — or a ref — holding the last value you actually processed. The effect runs, compares, and only calls setState when the value genuinely changed. A counter is visible and honest; a hidden loop limit just freezes the app mid-bug instead.