setState call inside useEffect (or componentDidUpdate) that’s missing a proper dependency array or a guard condition. Add the missing dependency array, or check state before updating it, and the error goes away.TL;DR
- Error #185 is React’s production-build code for “Maximum update depth exceeded.”
- It’s a real, officially documented error — you can look up any React error number at react.dev/errors.
- Root cause is almost always a state update that triggers itself again, usually inside
useEffectwithout a dependency array. - Fix by adding the correct dependency array, moving the state update to an event handler, or adding a condition that stops the update once state is already correct.
- Switch to React’s development build temporarily to get the full, unminified error and a component stack trace while you debug.
What Does “Minified React Error #185” Actually Mean?
In production builds, React strips out full error text to keep the bundle small, replacing it with a numbered code like Error #185. React’s own error decoder confirms the full message behind it: “Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.”
In plain terms: something in your component is updating state, that update triggers a re-render, and the re-render triggers the same state update again — forever. React catches this after a set number of nested updates and throws error #185 instead of freezing the tab.

Common Causes of Error #185
Every version of this bug traces back to a state update that re-triggers itself. Here’s how that usually happens in real codebases:
| Cause | Where It Shows Up | Fix |
|---|---|---|
Missing dependency array in useEffect |
Function components | Add [] or the correct dependencies |
setState in componentDidUpdate without a guard |
Class components | Compare previous and current props/state before updating |
| Two components updating each other’s state | Parent/child prop-drilling patterns | Lift shared state to one source of truth |
| Inline object/array passed as a dependency | useEffect / useMemo | Memoize with useMemo or move it outside the component |
| State update inside the render body itself | Function components | Move the update into an event handler or effect |
| Third-party widget re-rendering on every state change | Embedded dashboards, data grids | Check the widget’s own update/onChange handlers for loops |
How to Fix Error #185 (Step by Step)
1. Get the Full Error Message First
Before changing any code, run your app with the non-minified development build. It replaces the numeric code with the real message and a component stack trace, which tells you exactly which component is looping.
npm start
# or, if it's already built, check the source map
# in your browser's DevTools console
2. Add a Dependency Array to useEffect
This is the single most common cause. An effect with no dependency array runs after every render, and if it updates state, that update triggers another render, which runs the effect again.
// Before: runs on every render, loops forever
useEffect(() => {
setCount(count + 1);
});
// After: runs once, on mount
useEffect(() => {
setCount(count + 1);
}, []);
3. Guard State Updates in componentDidUpdate
In class components, always compare previous and current values before calling setState inside componentDidUpdate.
componentDidUpdate(prevProps) {
if (prevProps.userId !== this.props.userId) {
this.setState({ userId: this.props.userId });
}
}
4. Break Circular State Between Components
If a parent updates a child’s prop, and the child’s effect updates the parent’s state in response, you get a loop between two components. Lift the shared value into a single source of truth instead of syncing it back and forth.
5. Memoize Objects and Arrays Used as Dependencies
A new object or array literal is created on every render, so if you pass one directly into a useEffect dependency array, React sees it as “changed” every time and re-runs the effect endlessly.
// Before: options is a new object every render
const options = { limit: 10 };
useEffect(() => { fetchData(options); }, [options]);
// After: memoized, stable reference
const options = useMemo(() => ({ limit: 10 }), []);
useEffect(() => { fetchData(options); }, [options]);
- Always check your dependency array before adding a new
useEffect. - Never call a state setter directly in the render body without a condition.
- Trace the loop with React DevTools’ Profiler if the stack trace alone isn’t enough.
- Isolate third-party components — grids, calendars, and chart libraries are common offenders when their internal state syncs back to yours.
Frequently Asked Questions
Is React error #185 the same in every version of React?
Yes. The error code and its meaning, “Maximum update depth exceeded,” are consistent across React 16 through the current release, since the invariant is part of React’s core reconciliation safeguard rather than a version-specific feature.
Why do I see this error in third-party apps I didn’t build, like Steam or dashboard tools?
Any product built with React can hit this bug if its own developers have a state update loop somewhere in their code. Seeing it in a third-party app means it’s a bug on their end, not something you can fix from the outside — your best options are refreshing, clearing cache, or reporting it to that product’s support team.
Can I just increase React’s update limit instead of fixing the loop?
No — React doesn’t expose a setting to raise this limit, and doing so would only delay a browser freeze rather than prevent it. The limit exists specifically to catch loops before they crash the page.
Does this error affect server-side rendering (SSR)?
The infinite-loop pattern itself is a client-side rendering issue tied to state updates, so it typically surfaces after hydration on the client rather than during the server render pass, though the underlying component logic bug can exist in either environment.