Handling those unhandled promise rejections with JS async/await

Jonáš Jančařík
3 min readJun 6, 2018

--

2020 update: I updated the guide to reflect how the message has changed in the more recent versions of Node.js and I also shortened the post. If you are looking for the old version, you can find it in the Internet Archive.

The Problem

If you are seeing this error:

[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason “…”.] { code: ERR_UNHANDLED_REJECTION’ }

then what you are doing is likely this:

  • You put your code inside an async function in order to use await calls
  • One of your awaited functions fails (i.e. rejects a promise)
  • You get the error

Another possibility is that you know you need to catch the rejected promise. In this case, what might be happening is this:

  • You put your code inside an async function in order to use await calls
  • You put an await call inside a try/catch block or you use .catch()
  • The awaited function fails (i.e. rejects a promise)
  • You throw an error in the catch block to terminate the script
  • You get the error

In the first case, the key is this part of the error message:

… by rejecting a promise which was not handled with .catch().

The solution is simple, either use .catch() as suggested by the message:

await returnsPromise().catch(e => { console.log(e) })

Or use a try/catch block:

try {
await returnsPromise()
} catch (error) {
console.log('That did not go well.')
}

In the second case, the key part is this:

throwing inside of an async function without a catch block

Don’t throw inside of an async function without catching!

You may think that the warning is about the promise from the function you awaited and which failed, but actually it’s about the promise returned from the wrapper async function within which you are throwing an error. Async functions return promises implicitly.

Your options in this case are:

  • adding .catch() to your wrapper function call (you don’t even really need the try/catch block inside the wrapper then)
(async function () {
try {
await returnsPromise()
} catch (error) {
console.log('That did not go well.')
throw error
}
})().catch( e => { console.error(e) })
  • using process.exit(1) instead of throw to terminate the script (lazy but efficient…)
(async function () {try {
await returnsPromise()
} catch (error) {
console.error(error)
process.exit(1)
}
console.log('This will not be printed.');})()

Could it be cleaner?

If all you want is to terminate the script and display the error, you can simply get rid of the try/catch block altogether. The catch at the end of the IIFE will take care of the rejected promise from returnsPromise.

Again, this is a rather lazy solution which may backfire in a more complex script.

(async function () {  await returnsPromise()
console.log('This will not be printed.');
})().catch( e => { console.error(e) })

Do you always need to add the .catch() at the end of the IIFE?

Not if you catch and handle everything within the function.

If you want to terminate the script, you could catch the error and exit the process with process.exit(1) instead of using throw, like this with .catch() :

(async function () {await returnsPromise().catch((e) => { console.error(e); process.exit(1) })console.log('This will not be printed.');})()

or like this with try/catch :

(async function () {   try {
await returnsPromise()
} catch (error) {
console.error(error)
process.exit(1)
}
console.log('This will not be printed.');})()

But this gets a little repetitive if you have multiple awaits in your script.

Finally, just to be clear, if you want the script to continue, a .catch() or try/catch without a throw will be just fine. You can execute later parts of the code conditionally. For example, result below will be undefined:

(async function () {var result = await returnsPromise().catch((e) => { console.error(e.message) })console.log( result ? 'This was a success! ' + result : 'This was a failure.' )})()

--

--