-
Notifications
You must be signed in to change notification settings - Fork 29.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Promise rejection in timeout (versus module-level) treated as unhandled by debugger #53732
Comments
Yes, it is a debugger-specific issue caused by V8 "catch prediction". The debugger breaks synchronously when the promise is rejected. It would be okay if the debugger paused here when Related discussion: |
@nodejs/v8 |
Relatedly, the below code does not trip the debugger (with
setTimeout(async () => {
try {
Promise.reject()
} catch (e) { }
}) |
I think I figured out the node/lib/internal/modules/esm/module_job.js Lines 253 to 263 in 4b8000c
Because of this I raised an issue for this catch prediction false positive but it was regarded as "infeasible" here: https://issues.chromium.org/issues/352455689 When code escapes this call stack by running asynchronously, the inspector no longer regards it as handled by that Here's a demonstration: // assume this is in a .mjs file
// this function creates a Promise which is rejected and handled
// This promise is NOT regarded as "caught" by the V8's catch prediction
const makeRejectedPromise = (reason) => {
Promise.reject(reason).catch(() => {});
};
// rejection regarded as handled created synchronously:
makeRejectedPromise(1);
(async () => {
makeRejectedPromise(2);
})();
await null;
// or asynchronously after a module-level await
makeRejectedPromise(3);
// rejection regarded as unhandled when created asynchronously:
(async () => {
await null;
makeRejectedPromise(4);
})();
queueMicrotask(() => makeRejectedPromise(5));
process.nextTick(() => makeRejectedPromise(6));
setTimeout(() => makeRejectedPromise(7)); |
Version
v22.4.0
Platform
Subsystem
No response
What steps will reproduce the bug?
Create this script:
And run it in the debugger with
break on Uncaught
enabled.How often does it reproduce? Is there a required condition?
Every time. Note this does not happen if
Promise.reject()
is at top level instead of wrapped insetTimeout()
.What is the expected behavior? Why is that the expected behavior?
It is expected that the debugger does (1) not pause on such a promise or (2) only pauses on such a promise if
breakOnException
is enabled.The HTML spec guarantees that promise rejections are not considered unhandled if a handler is then synchronously attached.
What do you see instead?
Node breaks synchronously on the creation of the rejected promise. Similar issues happen when using the VSCode debugger and Chrome debugger.
Additional information
A downstream issue where this interferes with usage of the web streams API: #51093
I too have been incredibly confused by this, as it makes it seem like even correct usage of promises is developer error.
VSCode reports this as "Exception has occurred" instead of "promiseRejection".
The text was updated successfully, but these errors were encountered: