software-mansion / software-mansion/react-native-screens
[4.11.0-beta.1] Unhandled SoftException com.facebook.react.bridge.ReactNoCrashSoftException: Cannot get UIManager because the context doesn't contain an active CatalystInstance.
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 3.7k
- Forks
- 714
- Avg merge
- 2d 23h
- Merged PRs (30d)
- 71
Description
Description
Having this crash on a Samsung S22 running Android 14. Even though I use 4.11.0-beta.1 iirc this exists in previous versions too.
"react-native-reanimated": "3.17.3",
"react-native-gesture-handler": "2.25.0",
"@react-navigation/native": "7.1.6",
"@react-navigation/native-stack": "7.3.10",
"@react-navigation/stack": "7.2.10",`
Unhandled SoftException
com.facebook.react.bridge.ReactNoCrashSoftException: Cannot get UIManager because the context doesn't contain an active CatalystInstance.
at com.facebook.react.uimanager.UIManagerHelper.getUIManager(UIManagerHelper.java:82)
at com.facebook.react.uimanager.UIManagerHelper.getEventDispatcher(UIManagerHelper.java:134)
at com.facebook.react.uimanager.UIManagerHelper.getEventDispatcherForReactTag(UIManagerHelper.java:112)
at com.swmansion.rnscreens.ScreenFragment.onDestroy(ScreenFragment.kt:325)
at androidx.fragment.app.Fragment.performDestroy(Fragment.java:3376)
at androidx.fragment.app.FragmentStateManager.destroy(FragmentStateManager.java:812)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:346)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:114)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1455)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3034)
at androidx.fragment.app.FragmentManager.dispatchDestroy(FragmentManager.java:2988)
at androidx.fragment.app.Fragment.performDestroy(Fragment.java:3371)
at androidx.fragment.app.FragmentStateManager.destroy(FragmentStateManager.java:812)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:346)
at androidx.fragment.app.SpecialEffectsController$FragmentStateManagerOperation.complete(SpecialEffectsController.kt:664)
at androidx.fragment.app.SpecialEffectsController$Operation.cancel(SpecialEffectsController.kt:507)
at androidx.fragment.app.SpecialEffectsController.forceCompleteAllOperations(SpecialEffectsController.kt:293)
at androidx.fragment.app.SpecialEffectsController.executePendingOperations(SpecialEffectsController.kt:199)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1956)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1845)
at androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1751)
at androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:323)
at com.swmansion.rnscreens.ScreenContainer.onUpdate(ScreenContainer.kt:415)
at com.swmansion.rnscreens.ScreenContainer.performUpdates(ScreenContainer.kt:359)
at com.swmansion.rnscreens.ScreenContainer.performUpdatesNow(ScreenContainer.kt:351)
at com.swmansion.rnscreens.ScreenContainer.setFragmentManager(ScreenContainer.kt:137)
at com.swmansion.rnscreens.ScreenContainer.setupFragmentManager(ScreenContainer.kt:200)
at com.swmansion.rnscreens.ScreenContainer.onAttachedToWindow(ScreenContainer.kt:262)
at android.view.View.dispatchAttachedToWindow(View.java:23244)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3722)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3729)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3729)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3729)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3729)
at android.view.ViewGroup.addViewInner(ViewGroup.java:5604)
at android.view.ViewGroup.addView(ViewGroup.java:5352)
at android.view.ViewGroup.addView(ViewGroup.java:5292)
at com.facebook.react.views.view.ReactClippingViewManager.addView(ReactClippingViewManager.kt:36)
at com.facebook.react.views.view.ReactClippingViewManager.addView(ReactClippingViewManager.kt:20)
at com.facebook.react.uimanager.NativeViewHierarchyManager.manageChildren(NativeViewHierarchyManager.java:541)
at com.swmansion.reanimated.layoutReanimation.ReanimatedNativeHierarchyManager.manageChildren(ReanimatedNativeHierarchyManager.java:149)
at com.facebook.react.uimanager.UIViewOperationQueue$ManageChildrenOperation.execute(UIViewOperationQueue.java:194)
at com.facebook.react.uimanager.UIViewOperationQueue$1.run(UIViewOperationQueue.java:881)
2025-04-15 11:42:32.040 13830-13830 unknown:co...agerHelper com.APP_NAME E at com.facebook.react.uimanager.UIViewOperationQueue.flushPendingBatches(UIViewOperationQueue.java:994) (Ask Gemini)
at com.facebook.react.uimanager.UIViewOperationQueue.-$$Nest$mflushPendingBatches(Unknown Source:0)
at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.doFrameGuarded(UIViewOperationQueue.java:1054)
at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.kt:22)
at com.facebook.react.modules.core.ReactChoreographer.frameCallback$lambda$1(ReactChoreographer.kt:59)
at com.facebook.react.modules.core.ReactChoreographer.$r8$lambda$nSkFhrr5T7rop_XKwzlLov4NLLw(Unknown Source:0)
at com.facebook.react.modules.core.ReactChoreographer$$ExternalSyntheticLambda0.doFrame(D8$$SyntheticClass:0)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1688)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1699)
at android.view.Choreographer.doCallbacks(Choreographer.java:1154)
at android.view.Choreographer.doFrame(Choreographer.java:1070)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1647)
at android.os.Handler.handleCallback(Handler.java:958)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:230)
at android.os.Looper.loop(Looper.java:319)
at android.app.ActivityThread.main(ActivityThread.java:9063)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:588)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)
edit:
Now it showed up elsewhere after applying the patch, well that's a progress 😅
Unhandled SoftException
com.facebook.react.bridge.ReactNoCrashSoftException: Cannot get UIManager because the context doesn't contain an active CatalystInstance.
at com.facebook.react.uimanager.UIManagerHelper.getUIManager(UIManagerHelper.java:82)
at com.facebook.react.uimanager.UIManagerHelper.getEventDispatcher(UIManagerHelper.java:134)
at com.facebook.react.uimanager.UIManagerHelper.getEventDispatcherForReactTag(UIManagerHelper.java:112)
at com.th3rdwave.safeareacontext.SafeAreaProviderManagerKt.handleOnInsetsChange(SafeAreaProviderManager.kt:39)
at com.th3rdwave.safeareacontext.SafeAreaProviderManagerKt.access$handleOnInsetsChange(SafeAreaProviderManager.kt:1)
at com.th3rdwave.safeareacontext.SafeAreaProviderManager$addEventEmitters$1.invoke(SafeAreaProviderManager.kt:28)
at com.th3rdwave.safeareacontext.SafeAreaProviderManager$addEventEmitters$1.invoke(SafeAreaProviderManager.kt:28)
at com.th3rdwave.safeareacontext.SafeAreaProvider.maybeUpdateInsets(SafeAreaProvider.kt:21)
at com.th3rdwave.safeareacontext.SafeAreaProvider.onPreDraw(SafeAreaProvider.kt:39)
at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:1204)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:4786)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:3345)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:11437)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1690)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1699)
at android.view.Choreographer.doCallbacks(Choreographer.java:1154)
at android.view.Choreographer.doFrame(Choreographer.java:1080)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1647)
at android.os.Handler.handleCallback(Handler.java:958)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:230)
at android.os.Looper.loop(Looper.java:319)
at android.app.ActivityThread.main(ActivityThread.java:9063)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:588)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)
Steps to reproduce
I suspect this is happening between Fast Refresh but I had a user in production complaining that the app is frozen but they can scroll the lists (and this is exactly what happens locally). No interactions are possible even though the buttons trigger the events (have some console.log on them to test events).
I'll try this patch and see how it goes, it just checks if catalyst exists, will try it for a whole dev day and report back if I see it again.
react-native-screens+4.11.0-beta.1.patch
diff --git a/node_modules/react-native-screens/android/src/main/java/com/swmansion/rnscreens/ScreenContainer.kt b/node_modules/react-native-screens/android/src/main/java/com/swmansion/rnscreens/ScreenContainer.kt
index a275bc9..7746bb5 100644
--- a/node_modules/react-native-screens/android/src/main/java/com/swmansion/rnscreens/ScreenContainer.kt
+++ b/node_modules/react-native-screens/android/src/main/java/com/swmansion/rnscreens/ScreenContainer.kt
@@ -356,67 +356,73 @@ open class ScreenContainer(
return
}
needsUpdate = false
- onUpdate()
- notifyContainerUpdate()
+ if (context is ReactContext && (context as ReactContext).hasActiveReactInstance()) {
+ onUpdate()
+ notifyContainerUpdate()
+ }
}
open fun onUpdate() {
- createTransaction().let {
- // detach screens that are no longer active
- val orphaned: MutableSet<Fragment> =
- HashSet(
- requireNotNull(fragmentManager) {
- "fragment manager is null when performing update in ScreenContainer"
- }.fragments,
- )
- for (fragmentWrapper in screenWrappers) {
- if (getActivityState(fragmentWrapper) === ActivityState.INACTIVE &&
- fragmentWrapper.fragment.isAdded
- ) {
- detachScreen(it, fragmentWrapper.fragment)
+ if (context is ReactContext && (context as ReactContext).hasActiveReactInstance()) {
+ createTransaction().let {
+ // detach screens that are no longer active
+ val orphaned: MutableSet<Fragment> =
+ HashSet(
+ requireNotNull(fragmentManager) {
+ "fragment manager is null when performing update in ScreenContainer"
+ }.fragments,
+ )
+ for (fragmentWrapper in screenWrappers) {
+ if (getActivityState(fragmentWrapper) === ActivityState.INACTIVE &&
+ fragmentWrapper.fragment.isAdded
+ ) {
+ detachScreen(it, fragmentWrapper.fragment)
+ }
+ orphaned.remove(fragmentWrapper.fragment)
}
- orphaned.remove(fragmentWrapper.fragment)
- }
- if (orphaned.isNotEmpty()) {
- val orphanedAry = orphaned.toTypedArray()
- for (fragment in orphanedAry) {
- if (fragment is ScreenFragment) {
- if (fragment.screen.container == null) {
- detachScreen(it, fragment)
+ if (orphaned.isNotEmpty()) {
+ val orphanedAry = orphaned.toTypedArray()
+ for (fragment in orphanedAry) {
+ if (fragment is ScreenFragment) {
+ if (fragment.screen.container == null) {
+ detachScreen(it, fragment)
+ }
}
}
}
- }
- // if there is an "onTop" screen it means the transition has ended
- val transitioning = topScreen == null
-
- // attach newly activated screens
- var addedBefore = false
- val pendingFront: ArrayList<ScreenFragmentWrapper> = ArrayList()
-
- for (fragmentWrapper in screenWrappers) {
- val activityState = getActivityState(fragmentWrapper)
- if (activityState !== ActivityState.INACTIVE && !fragmentWrapper.fragment.isAdded) {
- addedBefore = true
- attachScreen(it, fragmentWrapper.fragment)
- } else if (activityState !== ActivityState.INACTIVE && addedBefore) {
- // we detach the screen and then reattach it later to make it appear on front
- detachScreen(it, fragmentWrapper.fragment)
- pendingFront.add(fragmentWrapper)
+ // if there is an "onTop" screen it means the transition has ended
+ val transitioning = topScreen == null
+
+ // attach newly activated screens
+ var addedBefore = false
+ val pendingFront: ArrayList<ScreenFragmentWrapper> = ArrayList()
+
+ for (fragmentWrapper in screenWrappers) {
+ val activityState = getActivityState(fragmentWrapper)
+ if (activityState !== ActivityState.INACTIVE && !fragmentWrapper.fragment.isAdded) {
+ addedBefore = true
+ attachScreen(it, fragmentWrapper.fragment)
+ } else if (activityState !== ActivityState.INACTIVE && addedBefore) {
+ // we detach the screen and then reattach it later to make it appear on front
+ detachScreen(it, fragmentWrapper.fragment)
+ pendingFront.add(fragmentWrapper)
+ }
+ fragmentWrapper.screen.setTransitioning(transitioning)
}
- fragmentWrapper.screen.setTransitioning(transitioning)
- }
- for (screenFragment in pendingFront) {
- attachScreen(it, screenFragment.fragment)
- }
+ for (screenFragment in pendingFront) {
+ attachScreen(it, screenFragment.fragment)
+ }
- it.commitNowAllowingStateLoss()
+ it.commitNowAllowingStateLoss()
+ }
}
}
protected open fun notifyContainerUpdate() {
- topScreen?.fragmentWrapper?.onContainerUpdate()
+ if (context is ReactContext && (context as ReactContext).hasActiveReactInstance()) {
+ topScreen?.fragmentWrapper?.onContainerUpdate()
+ }
}
}
Snack or a link to a repository
no repo, sorry, private app and not easy to repro anyway
Screens version
4.11.0-beta.1
React Native version
0.77.2
Platforms
Android
JavaScript runtime
Hermes
Workflow
React Native (without Expo)
Architecture
Paper (Old Architecture)
Build type
Debug mode
Device
Real device
Device model
Samsung S22 A14
Acknowledgements
Yes
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with android/src/main/java/com/swmansion/rnscreens/ScreenContainer.kt, especially performUpdates and onUpdate, then inspect ScreenFragment.kt around onDestroy. Reproduce the Android 14/Fast Refresh scenario and compare the reported UIManager stack traces. Done means the lifecycle transition no longer produces the SoftException or leaves interactions frozen; the issue also mentions SafeAreaProvider as another occurrence.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, kotlin, react-native
- Domain
- mobile-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 32/100