Maximum Update Depth Exceeded: How to Fix the React Error

The maximum update depth exceeded error means a state update keeps triggering itself. Move the update into an event handler or fix the Effect dependency.

7 min read

The maximum update depth exceeded error means a state update keeps triggering another update forever. React stops the loop and throws so the page does not freeze.

In current React the same bug often appears as "Too many re-renders. React limits the number of renders to prevent an infinite loop."

What the error means

React limits nested updates to prevent infinite loops. When a setter runs during render, or inside an Effect that fires after every render, each render schedules the next one until React gives up and throws. The limit protects the browser from an endless stream of work, and the loop underneath is still a real bug to fix.

The stack trace points at the setter that started the loop, which is the fastest way to find the culprit. Strict Mode does not cause this error, but it makes a render-time side effect appear sooner in development. Class components hit the same wall through setState inside componentDidUpdate without a guard.

Setting state during render

The clearest case is a setter called at the top level of the component body.

App.jsxApp.jsx
import { useState } from "react";
 
export default function Counter() {
  const [count, setCount] = useState(0);
 
  setCount(count + 1);
 
  return <p>Count: {count}</p>;
}

setCount runs on every render, which schedules another render, which runs setCount again. The fix is to move the update into an event handler so it only runs when the user acts.

App.jsxApp.jsx
import { useState } from "react";
 
export default function Counter() {
  const [count, setCount] = useState(0);
 
  return (
    <button onClick={() => setCount(count + 1)}>
      Count: {count}
    </button>
  );
}

Now the update happens once per click, and the loop is gone. The setter still lives in the component, but it only fires inside a handler, which is where user actions belong.

An Effect that fires every render

An Effect without a dependency array runs after every render, so setting state inside it loops too.

App.jsxApp.jsx
import { useEffect, useState } from "react";
 
export default function Counter() {
  const [count, setCount] = useState(0);
 
  useEffect(() => {
    setCount(count + 1);
  });
 
  return <p>Count: {count}</p>;
}

The Effect sets state, which triggers a render, which runs the Effect again. The fix is usually to remove the Effect, or to give it the dependency it actually needs.

Setting state after mount is rarely the right way to derive data. See you might not need an Effect for the alternatives.

The event handler mistake

A handler that runs during render looks almost the same as one that runs on click.

App.jsxApp.jsx
<button onClick={handleClick()}>Click me</button>

The parentheses call handleClick during render, so any state update inside it loops forever. Pass the function itself instead, and React calls it only when the user clicks the button.

App.jsxApp.jsx
<button onClick={handleClick}>Click me</button>

Verify the fix

Reload and interact with the component. The console should stay clean and the counter should move once per click, which is the proof the loop is gone. How to debug React applications systematically walks through isolating the offending setter when the stack is unclear.

Rune AI

Rune AI

Key Insights

  • The error means a state update triggers itself forever.
  • Move render-time updates into event handlers.
  • Give Effects a correct dependency array.
  • Pass handlers to onClick, never call them during render.
  • Strict Mode surfaces the loop faster in development.
RunePowered by Rune AI

Frequently Asked Questions

Is this error the same as too many re-renders?

Yes. Current React often reports it as 'Too many re-renders. React limits the number of renders to prevent an infinite loop.' Both point to a state update that repeats itself.

Where do I start looking?

Open the console stack and find the setter call that runs during render or inside an Effect that fires every render.

Conclusion

Maximum update depth exceeded means a state update loops forever. Remove render-time updates, fix Effect dependencies, and pass event handlers instead of calling them during render.