RootErrorBoundary behaviour after loading screen has been unmounted

I’m looking into the behaviour of RootErrorBoundary as it seems to do something unexpected in a particular scenario.

The ErrorBoundary is only mounted in development:

And it only seems to be concerned about errors that happen while the app loading screen is being displayed (so errors at startup):

If any errors happen in development during app startup either via the global handler, or via componentDidCatch(), the error is set as state of the component, causing a re-render with the error screen:

However, if an error happens after the app loading screen has unmounted the RootErrorBoundary seems unconcerned.

In GlobalUtils.errorHandler errors after app startup, this component has no side effects – those errors propagate as expected.

In componentDidCatch() errors after app startup, this component will catch the error, but not set any state, meaning render() doesn’t happen and the sub-tree is unmounted. The error is logged out with console.error() so you get the React Native red box, but after that is dismissed, there is a blank screen.

Is this intentional? The reason this seems unexpected to me is that because the error boundary doesn’t do anything with the error, it would make sense to let it propagate to the global error handler, which is what would happen if there was no error boundary installed.

The use case for this is for Bugsnag (I’m currently testing our Expo notifier) and it was surprising that throw new Error('An error') inside a render function of a component that is not mounted until after startup did not reach the global error handler, despite appearing to have crashed the app. As mentioned this is only in development, so isn’t a major problem, but a lot of our users test out our notifiers in development and this behaviour may well confuse them as it did us.

The following change would mean this component behaves more inline with my expectations, but I wanted to discuss here before making a PR:

    componentDidCatch(error: Error) {
      if (this._appLoadingIsMounted) {
        finishedAsync();

        this.setState({ error });
-     }
+     } else {
+       // Let the error propagate up to the global handler
+       throw error
+     }
-     console.error(error);
  }

This has the following consequence:

  • the RN red box is shown with this error
  • it is still logged out to the console by the default error handling logic
  • listeners on the global utils error handler (such as Bugsnag) get notified about this error

Which seems inkeeping with the existing behaviour, but keeping us happy too! Let me know your thoughts.

Cheers!

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.