308

For learning Angular 2, I am trying their tutorial.

I am getting an error like this:

(node:4796) UnhandledPromiseRejectionWarning: Unhandled promise rejection (r                                                                                                     ejection id: 1): Error: spawn cmd ENOENT
[1] (node:4796) 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.

I went through different questions and answers in SO but could not find out what an "Unhandled Promise Rejection" is.

Can anyone simply explain me what it is and also what Error: spawn cmd ENOENT is, when it arises and what I have to check to get rid of this warning?

Dem Pilafian
  • 5,625
  • 6
  • 39
  • 67
Mohammad Sadiqur Rahman
  • 5,379
  • 7
  • 31
  • 45
  • 3
    I missed this question! I'm so sorry for this warning it's confusing - we really improved it in newer Node.js and we're making the whole thing much better soon! – Benjamin Gruenbaum Jun 19 '18 at 20:19
  • Possible duplicate of: https://stackoverflow.com/questions/38265963/unhandled-promise-rejection-when-rejecting-promise-in-angular-2 – Christophe Roussy Aug 31 '18 at 14:38
  • @BenjaminGruenbaum, is it fixed yet? I got the same error on node v12.16.1 – Aven Desta Apr 15 '20 at 09:58
  • 1
    @Babydesta well, we show a better error now with a stack trace but we still don't crash node on unhandled rejections. We probably just need to open a PR to do that. – Benjamin Gruenbaum Apr 16 '20 at 10:14

9 Answers9

288

The origin of this error lies in the fact that each and every promise is expected to handle promise rejection i.e. have a .catch(...) . you can avoid the same by adding .catch(...) to a promise in the code as given below.

for example, the function PTest() will either resolve or reject a promise based on the value of a global variable somevar

var somevar = false;
var PTest = function () {
    return new Promise(function (resolve, reject) {
        if (somevar === true)
            resolve();
        else
            reject();
    });
}
var myfunc = PTest();
myfunc.then(function () {
     console.log("Promise Resolved");
}).catch(function () {
     console.log("Promise Rejected");
});

In some cases, the "unhandled promise rejection" message comes even if we have .catch(..) written for promises. It's all about how you write your code. The following code will generate "unhandled promise rejection" even though we are handling catch.

var somevar = false;
var PTest = function () {
    return new Promise(function (resolve, reject) {
        if (somevar === true)
            resolve();
        else
            reject();
    });
}
var myfunc = PTest();
myfunc.then(function () {
     console.log("Promise Resolved");
});
// See the Difference here
myfunc.catch(function () {
     console.log("Promise Rejected");
});

The difference is that you don't handle .catch(...) as chain but as separate. For some reason JavaScript engine treats it as promise without un-handled promise rejection.

bjb568
  • 11,089
  • 11
  • 50
  • 71
Daksh Gupta
  • 7,554
  • 2
  • 25
  • 36
  • 5
    It seems to work, if you add `myFunc = myFunct.then...` in the second example. – einstein Jan 29 '17 at 16:26
  • 2
    @einstein it will appear to work because you are recreating the same chain as in the first example: `var x = foo(); x = x.then(...); x = x.catch(...)` – randomsock Feb 27 '17 at 15:07
  • 6
    @einstein In your unchained example, when you say "For some reason Java Script engine treats it as promise without un-handled promise rejection", isn't this because and exception could be thrown in the `.then(() => {...})` which you **aren't** handling? I don't think this is doing the same thing as when you chain them. Is it? – Simon Legg Apr 07 '17 at 10:40
  • 16
    @DKG Regarding your second point, `catch` is a syntax sugar for `then(undefined, onRejected)`. Since your already called then on myfunc and that triggered an error, it's not going to call then(undefined, onRejected) on the same promise again. – Kevin Lee May 11 '17 at 17:54
  • i don't know if may be any of help but ... have you tryed var x=myFunc.then(){}; x.catch(){}. this is the exact chain written in 2 separated lines ... this should work. ok same answer from @randomsock. :) – Alex75 Dec 01 '19 at 06:43
  • Just `catch` no `then` works. The diff between chaining and not chaining has nothing to do with syntax. The JavaScript engine couldn't care less if you chain or not, so long as you neutralize all Promise instances. You can think of Promise instances as being prone to rejection or not. Doing `.catch` without rethrowing explicitly and by avoiding implicit throws (undefined doesn't have a member, etc.) inside ensures that it is neutralized. But: ``` const x = _some promise_; const y = x.then(() => {}); console.log(x !== y); // will be true ``` Y must **also** be neutralized. – Eduard Dumitru Mar 10 '23 at 10:20
  • You could also catch it inline eg. : `asyncFunc = async function(){ await new Promise(()=>{…}).catch((e)=>console.error(e)); };` – llange Mar 10 '23 at 19:13
57

This is when a Promise is completed with .reject() or an exception was thrown in an async executed code and no .catch() did handle the rejection.

A rejected promise is like an exception that bubbles up towards the application entry point and causes the root error handler to produce that output.

See also

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
32

Promises can be "handled" after they are rejected. That is, one can call a promise's reject callback before providing a catch handler. This behavior is a little bothersome to me because one can write...

var promise = new Promise(function(resolve) {
kjjdjf(); // this function does not exist });

... and in this case, the Promise is rejected silently. If one forgets to add a catch handler, code will continue to silently run without errors. This could lead to lingering and hard-to-find bugs.

In the case of Node.js, there is talk of handling these unhandled Promise rejections and reporting the problems. This brings me to ES7 async/await. Consider this example:

async function getReadyForBed() {
  let teethPromise = brushTeeth();
  let tempPromise = getRoomTemperature();

  // Change clothes based on room temperature
  let temp = await tempPromise;
  // Assume `changeClothes` also returns a Promise
  if(temp > 20) {
    await changeClothes("warm");
  } else {
    await changeClothes("cold");
  }

  await teethPromise;
}

In the example above, suppose teethPromise was rejected (Error: out of toothpaste!) before getRoomTemperature was fulfilled. In this case, there would be an unhandled Promise rejection until await teethPromise.

My point is this... if we consider unhandled Promise rejections to be a problem, Promises that are later handled by an await might get inadvertently reported as bugs. Then again, if we consider unhandled Promise rejections to not be problematic, legitimate bugs might not get reported.

Thoughts on this?

This is related to the discussion found in the Node.js project here:

Default Unhandled Rejection Detection Behavior

if you write the code this way:

function getReadyForBed() {
  let teethPromise = brushTeeth();
  let tempPromise = getRoomTemperature();

  // Change clothes based on room temperature
  return Promise.resolve(tempPromise)
    .then(temp => {
      // Assume `changeClothes` also returns a Promise
      if (temp > 20) {
        return Promise.resolve(changeClothes("warm"));
      } else {
        return Promise.resolve(changeClothes("cold"));
      }
    })
    .then(teethPromise)
    .then(Promise.resolve()); // since the async function returns nothing, ensure it's a resolved promise for `undefined`, unless it's previously rejected
}

When getReadyForBed is invoked, it will synchronously create the final (not returned) promise - which will have the same "unhandled rejection" error as any other promise (could be nothing, of course, depending on the engine). (I find it very odd your function doesn't return anything, which means your async function produces a promise for undefined.

If I make a Promise right now without a catch, and add one later, most "unhandled rejection error" implementations will actually retract the warning when i do later handle it. In other words, async/await doesn't alter the "unhandled rejection" discussion in any way that I can see.

to avoid this pitfall please write the code this way:

async function getReadyForBed() {
  let teethPromise = brushTeeth();
  let tempPromise = getRoomTemperature();

  // Change clothes based on room temperature
  var clothesPromise = tempPromise.then(function(temp) {
    // Assume `changeClothes` also returns a Promise
    if(temp > 20) {
      return changeClothes("warm");
    } else {
      return changeClothes("cold");
    }
  });
  /* Note that clothesPromise resolves to the result of `changeClothes`
     due to Promise "chaining" magic. */

  // Combine promises and await them both
  await Promise.all(teethPromise, clothesPromise);
}

Note that this should prevent any unhandled promise rejection.

anis programmer
  • 989
  • 1
  • 10
  • 25
17

"DeprecationWarning: Unhandled promise rejections are deprecated"

TLDR: A promise has resolve and reject, doing a reject without a catch to handle it is deprecated, so you will have to at least have a catch at top level.

Christophe Roussy
  • 16,299
  • 4
  • 85
  • 85
2

In my case was Promise with no reject neither resolve, because my Promise function threw an exception. This mistake cause UnhandledPromiseRejectionWarning message.

Diniz
  • 21
  • 1
2

I was seeing this when I had a util file with a Promised API call, a component that calls it but wasn't explicitly handling the .catch, and a Jest that was mocking up a Promise.reject: fetchStuff.mockImplementationOnce(() => Promise.reject(new Error('intentional fail')));

Furthermore, this was poisoning my mock, so that even though I was calling jest.resetAllMocks() before each test, the very next test would try render and that render would call the API, and it would fail. The test after would be back to a good state. I could swap around the order of my tests to prove that it would always poison the next render.

I tried handling the error in the API, but didn't succeed. I tried handling in my Jest mock, but that didn't work, either. What I ended up having to do was explicitly handle the .catch in my component.

  • How did you find your said promise which was causing this issue? I have the same issue, and I am not able to find it :-( – markus Sep 30 '22 at 07:22
1

I had faced a similar issue with NodeJS, where the culprit was a forEach loop. Note that forEach is a synchronous function (NOT Asynchronous). Therefore it just ignores the promise returned. The solution was to use a for-of loop instead: Code where I got the error:

UnhandledPromiseRejectionWarning: Unhandled promise rejection. 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()

is as follows:

permissionOrders.forEach( async(order) => {
        const requestPermissionOrder = new RequestPermissionOrderSchema({
            item: order.item,
            item_desc: order.item_desc,
            quantity: order.quantity,
            unit_price: order.unit_price,
            total_cost: order.total_cost,
            status: order.status,
            priority: order.priority,
            directOrder: order.directOrder
        });

        try {
            const dat_order = await requestPermissionOrder.save();
            res.json(dat_order);
        } catch(err){
            res.json({ message : err});
        }
    });

Solution for the above issue is as follows:

for (let order of permissionOrders){
        const requestPermissionOrder = new RequestPermissionOrderSchema({
            item: order.item,
            item_desc: order.item_desc,
            quantity: order.quantity,
            unit_price: order.unit_price,
            total_cost: order.total_cost,
            status: order.status,
            priority: order.priority,
            directOrder: order.directOrder
        });

        try {
            const dat_order = await requestPermissionOrder.save();
            res.json(dat_order);
        } catch(err){
            res.json({ message : err});
        }
    };
Dharman
  • 30,962
  • 25
  • 85
  • 135
Madhawa Jayagoda
  • 347
  • 4
  • 14
1

Try not closing the connection before you send data to your database. Remove client.close(); from your code and it'll work fine.

Rafia Zafar
  • 363
  • 1
  • 13
0

When I instantiate a promise, I'm going to generate an asynchronous function. If the function goes well then I call the RESOLVE then the flow continues in the RESOLVE handler, in the THEN. If the function fails, then terminate the function by calling REJECT then the flow continues in the CATCH.

In NodeJs are deprecated the rejection handler. Your error is just a warning and I read it inside node.js github. I found this.

DEP0018: Unhandled promise rejections

Type: Runtime

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.

Community
  • 1
  • 1
Κωλζαρ
  • 803
  • 1
  • 10
  • 22