BlogNotesAbout
moon indicating dark mode
sun indicating light mode

How to handle unhandledrejection errors using axios

March 02, 2020

TL;DR

Use this interceptor:

axios.interceptors.response.use(
response => response,
error => {
throw error;
}
);

The Backstory

I was looking at my error reports on Honeybadger today, and I came across this:

window.onunhandledrejection error screenshot

If you are like me, you are looking at that thinking… Okay, but what went wrong? As far as Honeybadger is concerned, the error is that we did not handle a promise rejection. The real issue, though, is that axios rejected because of a failed request. Unfortunately, we can’t tell what the failure was, because it is masked behind this unhandledrejection error.

What Is the Accepted Solution?

I went looking for a solution, and I came across this Github issue, which got me on the right track.

svpace mentioned that they were using this interceptor:

axios.interceptors.response.use(
response => response,
error => {
console.log(error.message);
return Promise.reject(error);
}

but it was not working as they expected. They were still encountering an unhandledrejection error.

I tried using that interceptor, and saw the exact same result they did, which makes sense.

Why Doesn’t This Work?

If you look at the interceptor, we are handling the rejection. In that handler, we log the error message, then move on. Unfortunately, though, the next thing the interceptor does is return another rejection. That rejection puts us right back where we started, with an unhandled rejection.

The Code

Your axios requests should look like one of the following:

const response = await axios.get("/some/path/or/url").catch(yourErrorHandler);

or

try {
const response = await axios.get("/some/path/or/url");
} catch (e) {
yourErrorHandler(e);
}

My error handler looks like this:

export function handleError(e) {
if (typeof Honeybadger !== "undefined") {
Honeybadger.notify(e);
} else {
throw e;
}
}

Also, I use the try/catch version of the code above.

Based on this, you can see that my axios.get call is failing, and e in the catch block is an unhandledrejection error, rather than the error axios encountered. That error is then reported to Honeybadger.

What Is the Solution That Will Work for Us?

As I mentioned, the Github issue put me on the right track. We definitely want to use an interceptor, as that is the only way I am aware of to handle the rejection. What should our interceptor look like though?

First, we want to pass successful resolutions along, so we start with this:

axios.interceptors.response.use(response => response);

Next, we need to add a rejection handler:

axios.interceptors.response.use(
response => response,
error => {}
);

What should we do in this handler? Let’s think about our goals:

  1. Get rid of the unhandledrejection error.
  2. Surface the actual error to our Promise.catch call, or the catch block if you are using try/catch.

The way to do this is to re-throw the original error, rather than reject again. To do that, we can update the interceptor to look like this:

axios.interceptors.response.use(
response => response,
error => {
// We really want to throw the error so it is handled and we don't get
// an unhandledrejection error. By throwing here, we are handling the
// rejection, and bubbling up to the closest error handler (try/catch or
// catch method call on a promise).
throw error;
}
);

Thanks For Reading, Friend

I hope you enjoyed this article, have a great day!


Brandon Conway
I enjoy learning about and writing code in many programming languages