How to Debug Exceptions with React Native

So you took the plunge. You decided to try out React Native.

So did I, and it’s awesome.

But as with all brand new shiny things, there are some rough edges.

React Native has an impressive set of developer tools. Pressing CMD+D on iOS will bring up the developer menu, you can then enable React Native debugging. React Native debugging requires the React Developer Tools Chrome extension, so go ahead and download it if you haven’t already.

Debug in Chrome

Select “Debug in Chrome.” Live Reload is also sweet.

After finishing this quick setup you’re good to go. You’re so excited to get started that you might even miss the line that says “Enable Pause On Caught Exceptions for a better debugging experience.” I know I did.

Pause on Caught Exceptions  Ignore “Pause on Caught Exceptions” at your own peril.

You can now open your console and debug like a pro. Source maps work, hot reload works, debug points work, everything just works.

Until you throw an asynchronous exception.

Screen Shot 2016-02-05 at 4.32.45 PM

React Native dev tools work like magic

In React Native exceptions are generally handled very well. For every error, you’ll see a giant red screen that tells you what went wrong and gives you a stack trace.

Screen Shot 2016-02-06 at 8.57.33 PM

The big red screen of death

But async errors don’t behave like that. If you’ll throw an error inside a promise or an async function you used to get nothing. As of React Native 0.19 you’ll get a small “yellow box” warning something bad happened.

Async JavaScript is tricky. Async JavaScript exceptions are even trickier. They’re all caught globally by Babel. So if for forgot to add .catch() to your promise or didn’t try/catch your async function, you’re going to have a bad time.

If only there was a way for the debugger to pause on globally caught exceptions…

So you checked the “pause on caught exceptions” checkbox and all was right the world. End of story right? Probably not for most.

You see I have a lot of extensions. And the problem with those extensions is that they throw caught errors. Which makes me sad.

After turning on “pause on caught exceptions” I would get 4-5 errors for every reload. It took me a while to realize my Chrome extensions are actually what causing the issue.

There are 2 easy ways to get around this:

  1. Open the UI Debugger in incognito mode. By default all extensions are blocked from running in incognito.
  2. Create a new chrome profile for debugging. Every chrome profile has its own extensions and you can start with a fresh profile.

So we’re done right? Can I go on debugging like a boss now?

Well, almost.

After doing all of the above I would still get this one annoying error every reload.

JavaScript Exception

WHY?!?!?!

What’s causing this issue is that React Native enables Flow by default. And I don’t use Flow. Because I don’t.

What we’re seeing is a failed 404 request made to Flow server, which is in charge of all of the Flow magic. The react-native-cli start manual clearly states that adding --skipflow should skip the flow check. In React 0.19 (latest release as of this writing) this is elegantly ignored.

But there is a way!

Screen Shot 2016-02-06 at 8.56.30 PM

I’m not proud to say I’m a little proud of this snippet

Diving into the code, I was able to “fool” React Native into failing silently. You can do the same with the following steps:

  1. Create a folder called “flow” in the root of your React Native Project
  2. Create a file called “index.html” inside it.
  3. Add the following JSON snippet inside 

That’s it! You should now be able to “pause on exception” like a true boss.