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.

Open
#2,873 34 comments 4 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

missing-repro platform:android
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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.