infinitered / infinitered/reactotron

Unhandled promise rejections

Open
#578 13 comments 4 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

request :+1:
Dominant language
TypeScript
Stars
15.6k
Forks
972
PR merge metrics
No merged PRs in 30d

Description

Problem

Async error reporting is an awful dev experience.

image

We don't get a red box, we get a yellow box with a string representation of the stack trace.

So let's pipe unhandled promise rejections into Reactotron as if they were normal synchronous errors.

image

Overview

Looks like there's a few ways to do this. Each more ghetto than the next. I'm ok with this.

Since 0.44 of React Native, they started tracking unhandled exceptions as a yellow box. In their promise module, they've got some hooks to inject in your own tracking. And this is what React Native does.

Option 1

This is how React Native gets their yellow box on the screen. In the onUnhandled, they do some pretty printing and display the error. Which is pretty much never what I personally want to see.

To me, an unhandled promise rejection is an error. Full stop.

In this implementation, we just report the error (which runs the source map lookup gauntlet).

if (__DEV__) {
  require("promise/setimmediate/rejection-tracking").enable({
    allRejections: true,
    onUnhandled: (id, error = {}) => {
      console.tron.reportError(error)
    },
    onHandled: () => {},
  })
}
Option 2

The problem with the first option is that it replaces the yellow box behaviour entirely. I'm not sure I'm cool with that. We don't want to diverge too far from what RN devs expect.

This implementation will do both. It'll log the error with Reactotron and still put up the yellow box. We just swizzle good ol' _87. 🤦‍♂️

A nice side-effect of this is that we don't have to wait for the hardcoded 2 second delay on most errors that flow thru unhandled promises.

Also, I'm not sure if error trackers like mobile center and crashlytics hook these same things, but if they do, this is the safer of the two options.

if (__DEV__) {
  const old87 = Promise._87
  const new87 = (promise, err) => {
    console.tron.reportError(err)
    old87(promise, err)
  }
  Promise._87 = new87
}
Option 3

There might be other ways to do this. I'm open to suggestions.

For example, we might be able to swizzle console.warn and parse it like that? Seems like it might be a bit fragile because we'd have to do some string parsing to filter unhandled rejections.

Where To Put This

Probably right inside the track error handling function in reactotron-react-native I'd reckon.

We could likely remove the if (__DEV__) parts since that should already be protected up at the app. Reactotron shouldn't be installed in production mode unless folks really want to. In which case, they know what they're doing.

Contributor guide

Open the contributing guide

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 in the error-handling function of reactotron-react-native and review React Native's promise rejection tracking hooks described in the issue. Determine which proposed integration preserves the expected development behavior, then verify that unhandled promise rejections are reported through Reactotron and the chosen React Native error display behavior remains intact.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, react-native
Domain
devtools, mobile-dev
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.