facebook/react · error · Error
Cannot setState on regular state inside a startGestureTransi
Error message
Cannot setState on regular state inside a startGestureTransition. Gestures can only update the useOptimistic() hook. There should be no side-effects associated with starting a Gesture until its Action is invoked. Move side-effects to the Action instead.
What it means
startGestureTransition(provider, scope) marks updates scheduled inside scope with a transition carrying a gesture flag, and the gesture contract allows only useOptimistic state to change during the gesture phase. requestUpdateLane inspects the current transition for every update; when it has a gesture flag and the update is a regular setState, React throws immediately, because gesture-phase side effects would break the optimistic-update and view-transition model.
Source
Thrown at packages/react-reconciler/src/ReactFiberWorkLoop.js:837
workInProgressRootRenderLanes !== NoLanes
) {
// This is a render phase update. These are not officially supported. The
// old behavior is to give this the same "thread" (lanes) as
// whatever is currently rendering. So if you call `setState` on a component
// that happens later in the same render, it will flush. Ideally, we want to
// remove the special case and treat them as if they came from an
// interleaved event. Regardless, this pattern is not officially supported.
// This behavior is only a fallback. The flag only exists until we can roll
// out the setState warning, since existing code might accidentally rely on
// the current behavior.
return pickArbitraryLane(workInProgressRootRenderLanes);
}
const transition = requestCurrentTransition();
if (transition !== null) {
if (enableGestureTransition) {
if (transition.gesture) {
throw new Error(
'Cannot setState on regular state inside a startGestureTransition. ' +
'Gestures can only update the useOptimistic() hook. There should be no ' +
'side-effects associated with starting a Gesture until its Action is ' +
'invoked. Move side-effects to the Action instead.',
);
}
}
if (__DEV__) {
if (!transition._updatedFibers) {
transition._updatedFibers = new Set();
}
transition._updatedFibers.add(fiber);
if (
hasPotentialUseWarnings() &&
resolveUpdatePriority() === DiscreteEventPriority
) {
// If we're updating inside a discrete event, then this might be a new user interaction
// and not just an automatically resolved loading sequence. Don't warn unless it happens again.View on GitHub (pinned to eafeac097b)
Solutions
- Keep only useOptimistic updates inside the startGestureTransition scope — the gesture-driven value must come from the useOptimistic hook
- Move every side effect out of the scope callback and into the Action that runs when the gesture commits
- If unrelated state must change when the gesture starts, update it before calling startGestureTransition or in the Action, never inside the scope
Example fix
// before
unstable_startGestureTransition(timeline, () => {
setSelected(true); // regular useState setter — throws
setOptimisticOffset(dx); // useOptimistic setter — allowed
});
// after
unstable_startGestureTransition(timeline, () => {
setOptimisticOffset(dx); // useOptimistic only
});
// side effects happen in the Action invoked when the gesture commits
function commitGesture() {
setSelected(true);
startTransition(() => setOffset(dragContext.current));
} Defensive patterns
Strategy: validation
Prevention
- Keep the startGestureTransition scope callback free of every setter except useOptimistic ones
- Put side effects in the Action that runs when the gesture commits, never in the start scope
- Keep the scope synchronous — an async scope is rejected separately
When it happens
Trigger: Calling any non-optimistic state update — a useState setter, useReducer dispatch, context provider write, or external store update that schedules a render — synchronously inside the startGestureTransition scope callback, before the gesture's Action runs.
Common situations: Wiring drag/press gestures where the handler also toggles unrelated UI state (selection, hover, menus) directly in the scope; migrating code from startTransition where side effects were tolerated; experimental builds with enableGestureTransition enabled.
Related errors
AI-assisted analysis of facebook/react@eafeac097b (2026-08-21).
Data as JSON: /api/errors/90c7120b49a63c2f.
Report an issue: GitHub.