Skip dropped mapped node in PropsAnimatedNode.updateView instead of crashing#57298
Conversation
…rashing A mapped child node can be removed from NativeAnimatedNodesManager (e.g. its component unmounted during a navigation transition) between animation frames while the prop node is still queued for an update. updateView() then calls requireNotNull on the missing node and throws IllegalArgumentException: "Mapped property node does not exist", crashing the app on a benign teardown race. Skip the stale node instead, mirroring the connectedViewTag == -1 early-return at the top of the method. Fixes react#37267.
|
Thank you for your pull request and welcome to our community. Action RequiredIn order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you. ProcessIn order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA. Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks! |
|
Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks! |
|
@fabriziocucci has imported this pull request. If you are a Meta employee, you can view this in D109253948. |
Summary
PropsAnimatedNode.updateView()iterates its mapped property nodes every frame and callsrequireNotNull(node) { "Mapped property node does not exist" }for each one. When a connected component is unmounted (for example during a navigation transition), its child animated nodes can be dropped fromNativeAnimatedNodesManagerwhile a frame callback for the prop node is still in flight. On the nextupdateViewthe mapped node is gone,requireNotNullthrows, and the app crashes:This is a teardown race: by the time the mapped node has been removed, the connected view is being torn down, so there is no meaningful value to write for that prop on this frame. This change skips a missing mapped node instead of throwing.
It mirrors the guard already at the top of the same method, which returns early when the view itself is gone (
connectedViewTag == -1), and matches the lenient behavior on iOS, whereRCTPropsAnimatedNodeiterates its parent nodes withisKindOfClass:checks and a missing (nil) node is simply skipped.Fixes #37267.
Changelog:
[ANDROID] [FIXED] - Prevent "Mapped property node does not exist" crash in
PropsAnimatedNode.updateViewwhen a mapped node is removed during an in-flight native animationTest Plan
The crash is a timing-dependent race, so it reproduces probabilistically rather than deterministically. Using the repro from #37267 (a screen with many simultaneous native-driver animations, navigating in and out repeatedly) and increasing Animator duration scale in Developer Options widens the window and makes it reproduce reliably on lower-end devices.
IllegalArgumentException: Mapped property node does not exist.continuefor the already-removed-node case, so no prop update is lost for live nodes.