facebook/react · error · Error
Cannot update optimistic state while rendering.
Error message
Cannot update optimistic state while rendering.
What it means
dispatchOptimisticState backs the setter returned by useOptimistic. If called while the owning component is rendering (isRenderPhaseUpdate(fiber) true), it throws when the throwIfDuringRender flag is set — unlike startTransition-during-render, which only warns because it predates the rule. Optimistic updates are input signals from event handlers/actions; they may never originate during render.
Source
Thrown at packages/react-reconciler/src/ReactFiberHooks.js:3796
: SyncLane;
const update: Update<S, A> = {
lane: lane,
// After committing, the optimistic update is "reverted" using the same
// lane as the transition it's associated with.
revertLane: requestTransitionLane(transition),
gesture: null,
action,
hasEagerState: false,
eagerState: null,
next: null as any,
};
if (isRenderPhaseUpdate(fiber)) {
// When calling startTransition during render, this warns instead of
// throwing because throwing would be a breaking change. setOptimisticState
// is a new API so it's OK to throw.
if (throwIfDuringRender) {
throw new Error('Cannot update optimistic state while rendering.');
} else {
// startTransition was called during render. We don't need to do anything
// besides warn here because the render phase update would be overidden by
// the second update, anyway. We can remove this branch and make it throw
// in a future release.
if (__DEV__) {
console.error('Cannot call startTransition while rendering.');
}
}
} else {
const root = enqueueConcurrentHookUpdate(fiber, queue, update, lane);
if (root !== null) {
// NOTE: The optimistic update implementation assumes that the transition
// will never be attempted before the optimistic update. This currently
// holds because the optimistic update is always synchronous. If we ever
// change that, we'll need to account for this.
startUpdateTimerByLane(lane, 'setOptimistic()', fiber);
scheduleUpdateOnFiber(root, fiber, lane);View on GitHub (pinned to eafeac097b)
Solutions
- Move the addOptimistic call into an event handler, form action, or transition callback
- If the goal is render-time behavior, render the merged view directly (compute base + pending during render) instead of dispatching
- Initialize the optimistic hook with the right fallback and only enqueue updates on user input
Example fix
// before
function List({todos}) {
const [shown, addOptimistic] = useOptimistic(todos);
if (todos.length === 0) addOptimistic(placeholder); // throws during render
return <ul>{shown.map(...)}</ul>;
}
// after
function List({todos}) {
const [shown, addOptimistic] = useOptimistic(todos, appendTodo);
// addOptimistic is only called from onSubmit / actions / transitions
return <ul>{shown.map(...)}</ul>;
} Defensive patterns
Strategy: try-catch
Try / catch
// Render-phase throw: boundary around optimistic components
<ErrorBoundary fallback={<PlainList/>} onError={(e) => warnDeveloper('addOptimistic called during render', e)}>
<OptimisticTodos />
</ErrorBoundary> Prevention
- Call addOptimistic only from event handlers, form actions, or transition callbacks
- Compute render-time derived state directly instead of enqueueing optimistic updates during render
- Initialize useOptimistic with the correct fallback so no render-time seed call is tempting
- When porting setState code, audit that every dispatch site is outside render
When it happens
Trigger: Calling addOptimistic(...) (the useOptimistic setter) in the component body, in a JSX expression or default parameter evaluated during render, or from any code that runs while React is rendering that component.
Common situations: Trying to derive optimistic state during render; converting a state toggle into useOptimistic without moving the dispatch out of render; optimistic UI code shared between render and handlers.
Related errors
- 349
- 485
- An unsupported type was passed to use(): ${String(usable)}
- Unknown Fiber. Needs to be a function component to inspect h
- 407
AI-assisted analysis of facebook/react@eafeac097b (2026-08-21).
Data as JSON: /api/errors/ba9414ae7875da0a.
Report an issue: GitHub.