A framework for building native applications using React
Fix Android Fabric Native Animated null prop crash (#56913)
Summary: This fixes an Android Fabric crash in the `overrideBySynchronousMountPropsAtMountingAndroid` path when Native Animated has stored a synchronous `transform` / `opacity` override and a later regular Fabric commit contains `null` for the same prop. | As-is | To-be | | --- | --- | | <img src="https://raw.githubusercontent.com/jingjing2222/react-native-fabric-transform-repro/main/crashed.gif" alt="Baseline Android Fabric transform crash repro" width="320" /> | <img src="https://raw.githubusercontent.com/jingjing2222/react-native-fabric-transform-repro/main/patched.gif" alt="Patched Android Fabric transform result" width="320" /> | | [crashed.gif](https://github.com/jingjing2222/react-native-fabric-transform-repro/blob/main/crashed.gif) | [patched.gif](https://github.com/jingjing2222/react-native-fabric-transform-repro/blob/main/patched.gif) | Native Animated can synchronously update `transform` / `opacity` on the UI thread. A regular Fabric commit for the same view may arrive later with stale props, including `transform: null` or `opacity: null`. Those regular Fabric null values should not clear the stored synchronous override, because the override may still represent the fresher Native Animated value. Before this patch, the override merge path assumed that the incoming Fabric prop had the same non-null type as the stored override. For example, a stored `transform` override is an array, but a regular Fabric update may contain `transform: null`. That mismatch could crash in `SurfaceMountingManager.overridePropsReadableMap`. This patch: - Allows regular Fabric `null` updates to be overridden by stored synchronous `transform` / `opacity` values instead of crashing. - Keeps regular Fabric `transform: null` / `opacity: null` from clearing the stored synchronous override. - Scopes synchronous null clearing to `transform` / `opacity` only. - Leaves null values for other props untouched, since other view prop nulls may be meaningful. This PR intentionally does not change Java Native Animated `restoreDefaultValues()` behavior. That restore implementation can be handled separately because changing it may affect existing apps. Repro repository: https://github.com/jingjing2222/react-native-fabric-transform-repro ## Why this is correct A regular Fabric `null` update is not enough to prove user intent to clear the native animated value, because it can be the stale commit produced after Native Animated already wrote a fresher value on the UI thread. In that case, the stored synchronous override should continue to win. If the synchronous Native Animated path explicitly sends `transform: null` or `opacity: null`, this patch treats that as a clear signal for that stored override key. The clear behavior is intentionally scoped to the props currently stored by this override path. ```text regular Fabric null: possible stale commit -> stored synchronous override wins synchronous transform / opacity null: explicit clear -> stored override key is removed other null props: left untouched ``` ## Changelog: [ANDROID] [FIXED] - Fix Android Fabric Native Animated crash when regular Fabric null props collide with stored synchronous transform or opacity overrides. Pull Request resolved: https://github.com/facebook/react-native/pull/56913 Test Plan: Added regression coverage for stale regular Fabric null commits and scoped synchronous null clears: - `updateProps_withNullOpacity_keepsStoredSynchronousProp` - `updateProps_withNullTransform_keepsStoredSynchronousProp` - `updatePropsSynchronously_withNullOpacity_removesStoredSynchronousProp` - `updatePropsSynchronously_withNullTransform_removesStoredSynchronousProp` Ran: ```sh ./gradlew :packages:react-native:ReactAndroid:testDebugUnitTest --tests com.facebook.react.fabric.SurfaceMountingManagerSynchronousMountPropsTest -Preact.internal.useHermesStable=true ``` Result: ```text BUILD SUCCESSFUL ``` Ran: ```sh ./gradlew :packages:react-native:ReactAndroid:testDebugUnitTest --tests com.facebook.react.animated.NativeAnimatedNodeTraversalTest -Preact.internal.useHermesStable=true ``` Result: ```text BUILD SUCCESSFUL ``` Ran: ```sh ./gradlew :packages:react-native:ReactAndroid:ktfmtCheck -Preact.internal.useHermesStable=true ``` Result: ```text BUILD SUCCESSFUL ``` Reviewed By: javache Differential Revision: D105974289 Pulled By: zeyap fbshipit-source-id: 7688cfa6b89f2d107c7ae58356864835d41f6add
J
jingjing2222 committed
4d36e57839d5e13584b13c14792d2d3e5182bcf2
Parent: 54b9af1
Committed by meta-codesync[bot] <215208954+meta-codesync[bot]@users.noreply.github.com>
on 5/26/2026, 4:01:52 PM