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:
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:
- Get rid of the
unhandledrejection
error. - Surface the actual error to our
Promise.catch
call, or thecatch
block if you are usingtry
/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!