facebook/react · error · Error
Rendered more hooks than during the previous render
Error message
Rendered more hooks than during the previous render
What it means
When a server render re-runs because of render-phase updates, Fizz reuses the hook list built in the previous pass. createHook throws when a re-render must allocate a hook beyond that list — the component called more hooks than the previous render, which is the Rules of Hooks violation 'never call hooks conditionally'.
Source
Thrown at packages/react-server/src/ReactFizzHooks.js:239
`[${nextDeps.join(', ')}]`,
`[${prevDeps.join(', ')}]`,
);
}
}
// $FlowFixMe[incompatible-use] found when upgrading Flow
for (let i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
// $FlowFixMe[incompatible-use] found when upgrading Flow
if (is(nextDeps[i], prevDeps[i])) {
continue;
}
return false;
}
return true;
}
function createHook(): Hook {
if (numberOfReRenders > 0) {
throw new Error('Rendered more hooks than during the previous render');
}
return {
memoizedState: null,
queue: null,
next: null,
};
}
function createWorkInProgressHook(): Hook {
if (workInProgressHook === null) {
// This is the first hook in the list
if (firstWorkInProgressHook === null) {
isReRender = false;
firstWorkInProgressHook = workInProgressHook = createHook();
} else {
// There's already a work-in-progress. Reuse it.
isReRender = true;
workInProgressHook = firstWorkInProgressHook;View on GitHub (pinned to eafeac097b)
Solutions
- Move every hook above conditionals and early returns so the same hooks run in the same order every render
- Replace conditional hooks with conditional use of results: call the hook unconditionally, then branch on its value
- Enable eslint-plugin-react-hooks (rules-of-hooks) so this class of bug fails statically
Example fix
// before
function Detail({item}) {
if (!item) return null;
const [tab, setTab] = useState(0); // hook after early return
return <div>{item[tab]}</div>;
}
// after
function Detail({item}) {
const [tab, setTab] = useState(0); // always called
if (!item) return null;
return <div>{item[tab]}</div>;
} Defensive patterns
Strategy: validation
Validate before calling
// .eslintrc: catch conditional hooks statically before any SSR run
// {
// "extends": ["plugin:react-hooks/recommended"]
// }
// Rules of Hooks violations (conditional hooks, early returns above hooks) fail lint instead of SSR. Prevention
- Keep all hooks above conditionals and early returns, in the same order every render
- Run eslint-plugin-react-hooks in CI so rules-of-hooks violations never reach SSR
- After refactors, check that no early return was introduced above an existing hook
When it happens
Trigger: Conditional hooks in a server-rendered component: if (cond) useState(...), a hook placed after an early return, or hooks inside loops with varying iteration counts. The violation surfaces on the re-render pass triggered by a render-phase update (a setter called during render).
Common situations: Client components with conditional hooks being SSR'd; refactors that introduce an early return above existing hooks; derived-state code whose setState during render triggers the second pass that exposes the order drift.
Related errors
- A function wrapped in useEffectEvent can't be called during
- startTransition cannot be called during server rendering.
- react-cache: read and preload may only be called from within
- 321
- 407
AI-assisted analysis of facebook/react@eafeac097b (2026-08-21).
Data as JSON: /api/errors/9a00a12efb5134ca.
Report an issue: GitHub.