-
Notifications
You must be signed in to change notification settings - Fork 63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Android error is not caught and reported #1050
Comments
TLDR: This isn't so much a bug, as a limitation of the way React Native integrates itself into Android. All of the other crash handers that I tested (Rollbar, Bugsnag, Sentry) also contain this issue, and none of them figured out a way to address it properly. We can't resolve it definitively, but we can implement some additional functionality to minify the pain. OK. An explanation. For a React Native application running on Android, we have three "origins" for exceptions.
1 and 3 are working fine. But 2, where errors are thrown by native Android code, on the main thread are never reported. The reason they aren't reported is because the only avenue we have, as a third-party library, to get a foothold into a exceptions is to set up a global handler for uncaught exceptions. Which is what we do. When Honeybadger initializes, it sets up a native Android exception handler to catch all native Android exceptions, and report them. This is what catches native exceptions thrown on a background thread (3, above). But it seems that on the main thread, either during initialization, or right before calling into native code, React Native wraps the call with a try/catch block, to make sure it catches any native errors during execution. It only does this on the main thread, which is why all exceptions thrown on the main thread are never caught by an "unhandled exception" handler; they are handled by React Native. In dev mode, when React Native catches these native exceptions, it shows the developer a nice stack trace. In production code, it either continues execution, if possible, or crashes, if not -- but it never seems to do the equivalent of a "rethrow", allowing some other handler (like our global handler) to do something with the exception (like send it to Honeybadger). During my investigation I tested other providers, namely Sentry, Rollbar, and BugSnag -- they all suffer from the same issue. Some of them have GitHub issues related to this going back several years. None of them have figured out a way to address this. So, this seems to be a limitation of the way React Native integrated into the Android environment. I could not figure out a way to resolve this completely. But, I think we can do something to minify the pain, or make it easier for developers in certain native context to still be able to deliver their exceptions to Honeybadger. I will look into adding some additional methods to the native-layer of the Honeybadger RN SDK (for Android only), that will at least allow developers who have access to their native code, to report exceptions to Honeybadger directly, rather than relying on the global exception handler. For those that may not have full control of their native code, they can also surround third-party native calls with try/catch and be able to deliver those exceptions to Honeybadger as well. So, we won't be able to close this gap 100%, but we can improve the situation. |
To clarify, you are saying that we cannot tap into unhandled exceptions thrown from the main thread, right? |
That’s correct. |
Native android errors are being caught and reported to Honeybadger when thrown this delayed manner, but not when thrown directly.
It appears that this directly thrown error never makes it to the javascript listener on
native-exception-event
, whereas the delayed error does.We theorize that the “direct” error crashes the app/process, and that the Android OS won’t let you report the error. In this case, the only way to work around that is by storing the exception info (i.e. persist on device) and reporting it to honeybadger when the app starts back up again. This is the experience @subzero10 had with Firebase Crashlytics, and it seems that this is still the case, as you can see here. Andrey found that this is the case with many of the other providers as well.
If we take the approach of persisting the error locally and then reporting it on next launch, care must be taken to make we don't make assumptions about when the exception took place via when it’s being reported. It seems like a non-optimal approach, but it is a better alternative to either not sending it or pushing it into a background thread and hoping it is kept in memory long enough to send.
The text was updated successfully, but these errors were encountered: