ChatGPT解决这个技术问题 Extra ChatGPT

How to find which promises are unhandled in Node.js UnhandledPromiseRejectionWarning?

Node.js from version 7 has async/await syntactic sugar for handling promises and now in my code the following warning comes up quite often:

(node:11057) UnhandledPromiseRejectionWarning: Unhandled promise 
rejection (rejection id: 1): ReferenceError: Error: Can't set headers 
after they are sent.
(node:11057) 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.

Unfortunately there's no reference to the line where the catch is missing. Is there any way to find it without checking every try/catch block?

You could use the Bluebird promise library and it would likely give you a stack trace.
Perhaps registering to Node's unhandledRejection event will help? See the docs. Your callback gets the Error object and the actual Promise, and I believe the Error object might hold a stack trace.
If the two previous comments don't help, then Can't set headers after they are sent. should give you a clue where in your code it could be happening (i.e. somewhere you are setting headers after the headers would've been already sent - presumably because of a failing in understanding asynchronous code, but that's a guess)
hi that messages helps for sure in finding where in the code the bug is, btw it's not as easy as knowing the line.
@jfriend00 It turns out it was a situation where an async function was throwing an error -- those internal Node promises for async functions don't use Bluebird, ever, so having Bluebird doesn't help in that scenario.

c
cuixiping

listen unhandledRejection event of process.

process.on('unhandledRejection', (reason, p) => {
  console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
  // application specific logging, throwing an error, or other logic here
});

Logging error.stack (or in the above example reason.stack) gives you the full stack trace of the error.
I wish I could say this worked, but it doesn't. I'm on Node 8.9.4.
I tried the above code and got undefined for both reason, and p? Any suggestions? " Unhandled Rejection at: Promise { state: 'rejected', reason: undefined } reason: undefined "
I added this code to the top of my node app.js file and nothing is logged unfortunately. Node v10.13.0.
Why the heck isn't this part of the default behavior of Node? I'm on v14.8.0 and it still shows the completely unhelpful messages even when I use --trace-warnings.
S
Sven Slootweg

The correct way to show a full stacktrace for unhandled ES6 Promise rejections, is to run Node.js with the --trace-warnings flag. This will show the full stacktrace for every warning, without having to intercept the rejection from within your own code. For example:

node --trace-warnings app.js

Ensure that the trace-warnings flag comes before the name of your .js file! Otherwise, the flag will be interpreted as an argument to your script, and it will be ignored by Node.js itself.

If you want to actually handle unhandled rejections (eg. by logging them), then you might want to use my unhandled-rejection module instead, which catches all the unhandled rejections for every major Promises implementation that supports it, with a single event handler.

That module supports Bluebird, ES6 Promises, Q, WhenJS, es6-promise, then/promise, and anything that conforms to any of the unhandled rejection specifications (full details in the documentation).


Using node 7.8.0 and all this gives me is a stack trace for a bunch of internal node modules. (node:10372) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): undefined at emitWarning (internal/process/promises.js:59:21) at emitPendingUnhandledRejections (internal/process/promises.js:86:11) at process._tickDomainCallback (internal/process/next_tick.js:136:7)
I don't see any output that shows where the unhandled promise issue is.
I added this to package.json start script and nothing was logged unfortunately. Node v10.13.0.
@user1063287 Ensure that the flag is in the correct place in your command. I've just added an update to the answer, to emphasize that it needs to go before the script name.
You're likely looking at the stack trace of the deprecation warning, not of the original unhandled error (which should be somewhere above the deprecation warning).
C
Community

Logging with stack trace

If you are looking for more of a helpful error message. Try adding this to your node file. It should display the full stack trace where your crash is happening.

process.on('unhandledRejection', (error, p) => {
  console.log('=== UNHANDLED REJECTION ===');
  console.dir(error.stack);
});

The only functional difference is doing a console.dir on the error's stack property. Quite a difference in output compared to the accepted answer.
I tried this but error.stack is undefined for me. :( node v14.15.4
This will only work when error is an instance of Error. It won't work if the promise is rejected with e.g. a string value: throw "Some error"
e
egekhter

This module allowed me to track down the culprit promise(s): https://www.npmjs.com/package/trace-unhandled

Install npm i trace-unhandled Include in code require('trace-unhandled/register');


Beautiful, plug'n play!
Node 14.19.1: didn't help, still getting at emitUnhandledRejectionWarning (internal/process/promises.js:170:15) (and that's the closest I get to the actual line)
D
DevTheJo

@Jeremy I had same result, the reason variable provided by

process.on('unhandledRejection', (reason, p) => {});

wasn't defined and it take me time to figure out that there were promise rejection providing nothing in my code, typically:

new Promise((resolve reject) => {
  const client = net.connect(options)
  client.on("connect", () => {
    resolve()
  })
  client.on("error", () => {
    reject()
  })
})

the problem is that you reject with nothing, to get trace you have to provide error, like this

new Promise((resolve reject) => {
  const client = net.connect(options)
  client.on("connect", () => {
    resolve()
  })
  client.on("error", (err) => {
    reject(err)
  })
})

and if you don't have error you can provide one yourself, even if empty, it will give a stack trace

reject(new Error())

If you need to find where the error was throwed from, look in your code for Promise with empty rejection