{"record":{"id":"f837e1835ef46b43","repo":"facebook/react","slug":"a-flushsync-update-cancelled-a-view-transition-bec","errorCode":null,"errorMessage":"A flushSync update cancelled a View Transition because it was called while the View Transition was still preparing. To preserve the synchronous semantics, React had to skip the View Transition. If you can, try to avoid flushSync() in a scenario that's likely to interfere.","messagePattern":"A flushSync update cancelled a View Transition because it was called while the View Transition was still preparing\\. To preserve the synchronous semantics, React had to skip the View Transition\\. If you can, try to avoid flushSync\\(\\) in a scenario that's likely to interfere\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/react-reconciler/src/ReactFiberWorkLoop.js","lineNumber":4671,"sourceCode":"let didWarnAboutInterruptedViewTransitions = false;\n\nexport function flushPendingEffectsDelayed(): boolean {\n  if (pendingDelayedCommitReason === IMMEDIATE_COMMIT) {\n    pendingDelayedCommitReason = DELAYED_PASSIVE_COMMIT;\n  }\n  return flushPendingEffects();\n}\n\nexport function flushPendingEffects(): boolean {\n  // Returns whether passive effects were flushed.\n  if (enableViewTransition && pendingViewTransition !== null) {\n    // If we forced a flush before the View Transition full started then we skip it.\n    // This ensures that we're not running a partial animation.\n    stopViewTransition(pendingViewTransition);\n    if (__DEV__) {\n      if (!didWarnAboutInterruptedViewTransitions) {\n        didWarnAboutInterruptedViewTransitions = true;\n        console.warn(\n          'A flushSync update cancelled a View Transition because it was called ' +\n            'while the View Transition was still preparing. To preserve the synchronous ' +\n            'semantics, React had to skip the View Transition. If you can, try to avoid ' +\n            \"flushSync() in a scenario that's likely to interfere.\",\n        );\n      }\n    }\n    pendingViewTransition = null;\n    pendingDelayedCommitReason = ABORTED_VIEW_TRANSITION_COMMIT;\n  }\n  flushGestureMutations();\n  flushGestureAnimations();\n  flushMutationEffects();\n  flushLayoutEffects();\n  // Skip flushAfterMutation if we're forcing this early.\n  flushSpawnedWork();\n  return flushPassiveEffects();\n}","sourceCodeStart":4653,"sourceCodeEnd":4689,"githubUrl":"https://github.com/facebook/react/blob/eafeac097ba51e1eab809c07102126bd5f8e5425/packages/react-reconciler/src/ReactFiberWorkLoop.js#L4653-L4689","documentation":"With View Transitions enabled (React's <ViewTransition> / startTransition({viewTransition: true})), a transition is 'pending' between React preparing it and the browser actually starting it. flushPendingEffects() runs on flushSync's synchronous commit path; if a flushSync arrives while a transition is still pending, React stops the transition via stopViewTransition() to avoid running a partial animation, records ABORTED_VIEW_TRANSITION_COMMIT, and — once per session, dev builds only — warns that flushSync cancelled the View Transition. The render and commit still happen; only the animation is skipped.","triggerScenarios":"Calling flushSync(fn) (ReactDOM.flushSync, a discrete sync update, or third-party code that forces a sync render) after a transition-wrapped update has been prepared but before the browser transition started — e.g. flushSync inside a layout effect or event handler that lands in the pending window of a startTransition with viewTransition.","commonSituations":"Mixing flushSync-based DOM measurement (editors, carousels, virtualized lists) with route/page transitions built on the View Transition API; calling flushSync inside or immediately after a transition callback; UI libraries that force synchronous renders colliding with navigation transitions.","solutions":["Remove flushSync for that update: wrap the state change in startTransition(() => setState(...)) (with the viewTransition option where applicable) so it stays concurrent.","Reorder so the synchronous update commits before the transition-wrapped update is triggered, keeping them out of the same pending window.","Defer genuinely-sync work (measurement) until after the transition has started — e.g. into a post-commit effect or requestAnimationFrame.","If the animation is cosmetic, accept the skip — React deliberately degrades rather than run a partial transition, and the commit itself succeeds."],"exampleFix":"// before\nfunction onNext() {\n  startTransition(() => setPage(next)); // prepares a View Transition\n  flushSync(() => setHighlight(true)); // lands while pending -> transition skipped\n}\n\n// after\nfunction onNext() {\n  flushSync(() => setHighlight(true)); // sync work commits first\n  startTransition(() => setPage(next)); // transition starts undisturbed\n}","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never call flushSync inside or immediately after triggering a transition-wrapped update; order sync updates first, then startTransition.","Use startTransition (optionally with the viewTransition option) for state that drives the animated subtree.","Move DOM measurement that needs sync results into layout effects that run before the transition is prepared, or into requestAnimationFrame after it starts.","Audit third-party UI libraries for internal flushSync calls when adopting View Transitions."],"tags":["react-19","view-transitions","flushsync","concurrency"],"backgroundTag":"flushsync-skips-view-transition","analyzedSha":"eafeac097ba51e1eab809c07102126bd5f8e5425","analyzedAt":"2026-08-21T22:01:08.818Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}