react-native-gesture-handler: Could not find root view for a given ancestor with tag

Description

We are seeing the following crash on Android:

com.facebook.react.bridge.JSApplicationIllegalArgumentException: Could find root view for a given ancestor with tag 3199
    at com.swmansion.gesturehandler.react.RNGestureHandlerModule.tryInitializeHandlerForReactRootView(RNGestureHandlerModule.java:18)
    at com.swmansion.gesturehandler.react.RNGestureHandlerModule.attachGestureHandler(RNGestureHandlerModule.java:1)
    at java.lang.reflect.Method.invoke(Method.java)
    at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:18)
    at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:2)
    at com.facebook.react.bridge.queue.NativeRunnable.run(NativeRunnable.java)
    at android.os.Handler.handleCallback(Handler.java:869)
    at android.os.Handler.dispatchMessage(Handler.java:101)
    at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:1)
    at android.os.Looper.loop(Looper.java:206)
    at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:8)
    at java.lang.Thread.run(Thread.java:764)

Screenshots

Screenshot 2021-10-04 at 17 09 33

Steps To Reproduce

I was not able to reproduce it consistently, but it seems to happen after the app goes to foreground.

Package versions

  • React: 17.0.1
  • React Native: >= 0.64.2
  • React Native Gesture Handler: 1.10.3
  • React Navigation: 5.14.4

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 21
  • Comments: 51

Commits related to this issue

Most upvoted comments

+1

I was able to resolve this issue in my project. The problem is that Codepush.restartApp doesn’t actually restart the app. Instead, it uses the ReactNativeInstanceManager class to reload the bundle:

https://github.com/facebook/react-native/blob/4fb49cd555942caba1515b6a03f8ccea931dfc90/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java#L435

This means that if any RN-GestureHandler components begin initializing before a Codepush.restartApp, there is a very good chance that when they finish., the RootNode doesn’t exist anymore. This is what causes the crash.

To solve this, you have to make sure there are no instances of RN-GestureHandler in the process of loading before a Codepush.restartApp operation. This includes things like react-navigation, which will mount gesture handlers behind the scenes.

In our case, when our app loads we begin a codepush sync. While the codepush is in any of these states, we render a simple View with no gesture handlers or react-navigation are mounted: CHECKING_FOR_UPDATE, DOWNLOADING_PACKAGE, UPDATE_INSTALLED, INSTALLING_UPDATE.

Only after the codepush is completely finished, it’s safe to mount any react-navigation components.

The error doesn’t say “Could not find” but “Could find”.

Does anyone have steps that we can follow to consistently reproduce this bug? (ideally in an emulator)

This may not really be a fix, but we found a workaround for this that is working well for us. We are using:

"react-native": "0.66.1",
"react-native-gesture-handler": "1.8.0",
  1. Remove the Override in MainActivity.java:
-  @Override
-  protected ReactActivityDelegate createReactActivityDelegate() {
-    return new ReactActivityDelegate(this, getMainComponentName()) {
-      @Override
-      protected ReactRootView createRootView() {
-       return new RNGestureHandlerEnabledRootView(MainActivity.this);
-      }
-    };
-  }
  1. Add the GestureHandlerRootView to your app.
+ import { GestureHandlerRootView } from "react-native-gesture-handler";

...

+ <GestureHandlerRootView style={{ flex: 1 }}>
+   <App/>
+ </GestureHandlerRootView>
  1. This step might not be necessary and probably not recommended by the library authors, but we also forked our own version and made the following changes to RNGestureHandlerModule.java:
- throw new JSApplicationIllegalArgumentException("Could find root view for a given ancestor with tag "
              + ancestorViewTag);

… and just return instead of throwing. Honestly we’re not exactly sure of the ramifications of this, but the app seems to behave normally in this scenario.

+ return;

@systemride have you discovered any issues related to your workaround?

So far we have not discovered any other issues to our workaround but it’s still something we want to revisit.

Also maybe worth noting… that while we don’t use codepush, we do use react-native-restart which might do something similar to codepush.

@federicot You asked if another user was using Codepush.

Are you aware of a relationship between Codepush and this crash?

My team is seeing an increase in crashes with this stacktrace, and it’s not clear to us why. Unlike @systemride , we are using Codepush, and the crashes seem to have increased after a Codepush.

Our team is also using Codepush. Crashes with this stack trace is pretty common after a codepush restart on Android. We have our app wrapped in GestureHandlerRootView, but maybe something about the codepush restart causes this to become unmounted? I’m planning on looking more into it this week.

+1

hi @LFMAKER @brduck are you guys find a way to solve this on expo?

we found a way to test this out. In our case, our codePush installMode uses the ON_NEXT_RESUME strategy, so after downloading the codePush update it is installed when user comes back to the foreground.

  1. Launch an android emulator with low resources (in our case, 343 MB of RAM, 48PB of VM heap, 2 multi-core CPU)
  2. Find a way to trigger attaching a new gesture handler. In our case, it was enough to navigate to other screen when the app state changes from background to active.
  3. Release an update to CodePush so you can download it in your app.
  4. Launch your app and wait for the CodePush update to be downloaded
  5. Set app to the background
  6. Come back to the foreground
  7. At this point the race condition pointed out by @jbaudanza should happen and the app crashes.

Hope this helps

We have a lot of these crashes but we do not use codepush so while it seems to be triggered by a codepush restart it can also happen in apps that do not use codepush at all.

I have the same problem with code push in production. What I don’t understand is that it is not systematic and in staging we are not able to reproduce it.

@systemride Thanks for sharing. Are you also using codepush?

No, not using codepush.

Well, unfortunately, your trick won’t do for me, my app goes completely blank

I updated my comment, you might also try adding flex styles to the component. Eg:

<GestureHandlerRootView style={{ flex: 1 }}>

+1

com.facebook.react.bridge.JSApplicationIllegalArgumentException: Could find root view for a given ancestor with tag 6343
        at com.swmansion.gesturehandler.react.RNGestureHandlerModule.tryInitializeHandlerForReactRootView(RNGestureHandlerModule.java:18)
        at com.swmansion.gesturehandler.react.RNGestureHandlerModule.attachGestureHandler(RNGestureHandlerModule.java:1)
        at java.lang.reflect.Method.invoke(Method.java:-2)
        at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:18)
        at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:13)
        at com.facebook.react.bridge.queue.NativeRunnable.run(NativeRunnable.java:-2)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:1)
        at android.os.Looper.loop(Looper.java:214)
        at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:8)
        at java.lang.Thread.run(Thread.java:919)