Description
Version
15.x.x, 16.x.x, 17.x.x
Platform
Darwin ItamarGro-2.local 20.6.0 Darwin Kernel Version 20.6.0: Mon Aug 30 06:12:21 PDT 2021; root:xnu-7195.141.6~3/RELEASE_X86_64 x86_64
Subsystem
No response
What steps will reproduce the bug?
Node doesn't seem to add relevant stack trace information to where the error occurred in the case of unhandled rejection with a value that is not instance of Error
.
This is a case that reproduces this undesired behavior:
run this with node index.js
:
// index.js
function notOk() {
return Promise.reject("Uh-oh!");
}
notOk();
The output of this script is:
node:internal/process/promises:246
triggerUncaughtException(err, true /* fromPromise */);
^
[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 "Uh-oh!".] {
code: 'ERR_UNHANDLED_REJECTION'
}
This is problematic because in the output above there's simply no information to help me understand where the error occurred.
In such a small script it is obvious where the problem is but in a larger codebase it's basically impossible to find.
I found it only by debugging and running through the functions.
In contrast, rejecting with a value that is an instance of Error
will throw a stack trace correctly:
// index.js
function ok() {
return Promise.reject(new Error("OK!"));
}
ok();
This script will output:
/Users/itamar/projects/test/index.js:2
return Promise.reject(new Error("OK!"));
^
Error: OK!
at ok (/Users/itamar/projects/test/index.js:2:25)
at Object.<anonymous> (/Users/itamar/projects/test/index.js:5:1)
at Module._compile (node:internal/modules/cjs/loader:1101:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
at Module.load (node:internal/modules/cjs/loader:981:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:17:47
In this case i know where the problem is and i can fix it.
How often does it reproduce? Is there a required condition?
It reproduces in node 15, 16 and 17 (with default value for flag --unhandled-rejections=throw
and not --unhandled-rejections=warn-with-error-code
or some other option) on every unhandled rejection with a value that is not instance of error.
What is the expected behavior?
It would be nice to at least get a stack trace to the place in my code where the reject happened.
something like this:
/Users/itamar/projects/test/index.js:2
return Promise.reject("Uh-oh!");
^
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 "Uh-oh!"
at ok (/Users/itamar/projects/test/index.js:2:25)
at Object.<anonymous> (/Users/itamar/projects/test/index.js:5:1)
at Module._compile (node:internal/modules/cjs/loader:1101:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
at Module.load (node:internal/modules/cjs/loader:981:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:17:47
What do you see instead?
I see a non descriptive error message that doesn't explain clearly where the problem is:
node:internal/process/promises:246
triggerUncaughtException(err, true /* fromPromise */);
^
[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 "Uh-oh!".] {
code: 'ERR_UNHANDLED_REJECTION'
}
Additional information
Basically the mechanism for throwing on uncaught rejections is nice but i think it's missing handling those edge cases where reject value isn't a native error.