Repository navigation
Description
Description
With enableViewRecycling on, ViewManager.onDropViewInstance pools a view even when view.getParent() != null. A removed view keeps its parent when the parent called ViewGroup.startViewTransition(child) first, as exit animations do, and if that parent leaves the window before calling endViewTransition, dispatchDetachedFromWindow empties its disappearing children without clearing the child's parent. When the pool hands that view out again, addViewAt crashes with "The specified child already has a parent". #59776 doesn't help once the old parent has left the window, because endViewTransition only clears the parent of a view that is still one of its disappearing children. We hit this through react-native-screens, which starts a transition on every view in a screen it pops but never ends the ones below the screen (software-mansion/react-native-screens#3249). We ship a one-line fix in onDropViewInstance: don't pool the view when view.getParent() != null.
Steps to reproduce
- Clone https://github.com/mozzius/view-recycling-transition-repro, then
cd ReproducerApp && yarn install && yarn android --mode release. - Press Run. It removes a child from
TransitionContainer(a small native container that callsstartViewTransitionbefore removing a child andendViewTransition1 s later), removes the container 300 ms later, and mounts new views 300 ms after that. - With
enableViewRecyclingon (the default; the switch at the top toggles it and restarts the app), the app crashes. With it off, the new views appear.
React Native Version
0.90.0-nightly-20261108-f480836ad
Affected Platforms
Runtime - Android, Build - MacOS
Areas
Fabric - The New Renderer
Output of npx @react-native-community/cli info
System:
OS: macOS 27.2
CPU: (14) arm64 Apple M4 Pro
Memory: 110.41 MB / 48.00 GB
Shell:
version: 5.3.20
path: /opt/homebrew/bin/bash
Binaries:
Node:
version: 24.22.1
path: /Users/samuel/.nvm/versions/node/v24.22.1/bin/node
Yarn:
version: 1.22.22
path: /Users/samuel/.nvm/versions/node/v24.22.1/bin/yarn
npm:
version: 11.19.1
path: /Users/samuel/.nvm/versions/node/v24.22.1/bin/npm
Watchman:
version: 2026.10.26.00
path: /opt/homebrew/bin/watchman
Managers:
CocoaPods:
version: 1.17.0
path: /Users/samuel/.rbenv/shims/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 27.2
- iOS 27.2
- macOS 27.2
- tvOS 27.2
- visionOS 27.2
- watchOS 27.2
Android SDK:
API Levels:
- "29"
- "33"
- "34"
- "35"
- "36"
- "37"
Build Tools:
- 30.0.3
- 34.0.0
- 35.0.0
- 35.0.1
- 36.0.0
- 37.0.0
System Images:
- android-28 | Google ARM64-V8a Play ARM 64 v8a
- android-29 | Google Play ARM 64 v8a
- android-30 | Google APIs ARM 64 v8a
- android-34 | Google Play ARM 64 v8a
- android-35 | Google Play ARM 64 v8a
- android-35 | Google Play Tablet ARM 64 v8a
- android-36 | Google Play ARM 64 v8a
Android NDK: Not Found
IDEs:
Android Studio: 2026.1 AI-261.26222.65.2614.16379836
Xcode:
version: 27.2/27B52
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.21.0.3
path: /usr/bin/javac
Ruby:
version: 2.7.6
path: /Users/samuel/.rbenv/shims/ruby
npmPackages:
"@react-native-community/cli":
installed: 21.0.0-alpha.1
wanted: 21.0.0-alpha.1
react:
installed: 19.3.0
wanted: 19.3.0
react-native:
installed: 0.90.0-nightly-20261108-f480836ad
wanted: 0.90.0-nightly-20261108-f480836ad
react-native-macos: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: true
newArchEnabled: true
iOS:
hermesEnabled: Not found
newArchEnabled: false
Stacktrace or Logs
E SurfaceMountingManager: java.lang.IllegalStateException: addViewAt: cannot insert view [54] into parent [1]: View already has a parent: [24] Parent: TransitionContainer View: ReactViewGroup
FATAL EXCEPTION: main
java.lang.IllegalStateException: addViewAt: failed to insert view [54] into parent [1] at index 13
at com.facebook.react.fabric.mounting.SurfaceMountingManager.addViewAt(SurfaceMountingManager.kt:376)
at com.facebook.react.fabric.mounting.mountitems.IntBufferBatchMountItem.execute(IntBufferBatchMountItem.kt:122)
at com.facebook.react.fabric.mounting.MountItemDispatcher.executeOrEnqueue(MountItemDispatcher.kt:438)
at com.facebook.react.fabric.mounting.MountItemDispatcher.dispatchMountItems$lambda$4(MountItemDispatcher.kt:324)
at com.facebook.react.fabric.mounting.MountItemDispatcher$$ExternalSyntheticLambda4.invoke(D8$$SyntheticClass:0)
at com.facebook.react.internal.tracing.PerformanceTracer.trace(PerformanceTracer.kt:46)
at com.facebook.react.internal.tracing.PerformanceTracer.trace(PerformanceTracer.kt:35)
at com.facebook.react.fabric.mounting.MountItemDispatcher.dispatchMountItems(MountItemDispatcher.kt:295)
at com.facebook.react.fabric.mounting.MountItemDispatcher.tryDispatchMountItems(MountItemDispatcher.kt:131)
at com.facebook.react.fabric.FabricUIManager$DispatchUIFrameCallback.doFrameGuarded(FabricUIManager.java:1737)
at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.kt:42)
at com.facebook.react.modules.core.ReactChoreographer.frameCallback$lambda$0(ReactChoreographer.kt:59)
at com.facebook.react.modules.core.ReactChoreographer$$ExternalSyntheticLambda0.doFrame(D8$$SyntheticClass:0)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1568)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1579)
at android.view.Choreographer.doCallbacks(Choreographer.java:1179)
at android.view.Choreographer.doFrame(Choreographer.java:1104)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1553)
at android.os.Handler.handleCallback(Handler.java:995)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loopOnce(Looper.java:248)
at android.os.Looper.loop(Looper.java:338)
at android.app.ActivityThread.main(ActivityThread.java:9067)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:593)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:932)
Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
at android.view.ViewGroup.addViewInner(ViewGroup.java:5289)
at android.view.ViewGroup.addView(ViewGroup.java:5118)
at android.view.ViewGroup.addView(ViewGroup.java:5058)
at com.facebook.react.uimanager.ViewGroupManager.addView(ViewGroupManager.kt:29)
at com.facebook.react.uimanager.ViewGroupManager.addView(ViewGroupManager.kt:15)
at com.facebook.react.fabric.mounting.SurfaceMountingManager.addViewAt(SurfaceMountingManager.kt:373)
... 25 more
MANDATORY Reproducer
https://github.com/mozzius/view-recycling-transition-repro
Screenshots and Videos
No response
Activity