Unhandled promise rejection despite catching the promise

Viewed 5163

I don't understand... Is it me or is this a bug in node?

This is fine as expected:

const a = new Promise((resolve, reject) => {
  setTimeout(() => reject('timeout'), 1000);
});
a.catch(console.log);

And this is throwing a warning:

const a = new Promise((resolve, reject) => {
  setTimeout(() => reject('timeout'), 1000);
});
a.then(console.log);
a.catch(console.log);

I get

timeout
(node:40463) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): timeout
(node:40463) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
3 Answers

Using .then(...) with a promise returns a new promise (that's called chaining). Therefore, when you do something like:

a.then(console.log); // line 1 creates a new promise "b"
a.catch(console.log); // line 2 handles rejection on promise "a"

where a is your initial promise, you're creating a new promise on line 1 (one that is not a anymore. let's call it b). So even though you're using .catch(...) with a, you're not handling the rejection on b, which explains the message you're seeing on console.

To avoid this message, you should add a .catch(...) to this new promise b, on line 1

Annotated and slightly modified source:

// promise A is created
const a = new Promise((resolve, reject) => {
  setTimeout(() => reject('timeout'), 1000);
});

// promise A is chained with .then()
// means new promise is created
// and only resolve catched here
const aThenPromise = a.then(console.log);

// promise A is chained with .catch()
// means new promise is created
// and only reject catched here
const aCatchPromise = a.catch(console.log);

// aThenPromise !== aCatchPromise

When promise a is rejected:

  • aCatchPromise works as expected, and timeout is logged to console
  • aThenPromise does nothing, as it works only with resolve(), and reject is passed through it, and not handled because it is different Promise. This leads to UnhandledRejection

You need to add catch to aThenPromise,

One possible option is a.then(console.log).catch(console.log) this will handle rejection passed through .then

Promise work as a chain of action, if you spite the action, it will not work.

a.then(console.log).catch(console.log);

Related