Skip to content
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

lib: ensure every unhandled promise reason is wrapped in an error #21372

Closed
wants to merge 1 commit into from

Conversation

jd-carroll
Copy link

This change adds more debugging context to any unhandled promise.
If the unhandled promise does not have a reason which is an error,
it is very difficult to determine where the error came from. This
ensures every reason has an appropriate stack trace before the
"next_tick" when the stack is lost.

Refs: #16768

If people like this change, I will happily add any tests/documentation as well.

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows [commit guidelines]

This change adds more debugging context to any unhandled promise.
If the unhandled promise does not have a reason which is an error,
it is very difficult to determine where the error came from.  This
ensures every reason has an appropriate stack trace before the
"next_tick" when the stack is lost.

Refs: nodejs#16768
@devsnek
Copy link
Member

devsnek commented Jun 16, 2018

i would say that this should only be done if the rejection value is a string, and even then i wouldn't be enthusiastic about the coercion to an error.

@devsnek devsnek added promises Issues and PRs related to ECMAScript promises. errors Issues and PRs related to JavaScript errors originated in Node.js core. labels Jun 16, 2018
Copy link
Member

@Trott Trott left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, @jd-carroll! Welcome, and thanks for the pull request! This will need a test before landing. If you want to try to write the test yourself, there is a guide in https://github.com/nodejs/node/blob/master/doc/guides/writing-tests.md. It's also possible that if this feature/change gets support, someone else might offer up a test, as I imagine the test file for this would be short.

@jd-carroll
Copy link
Author

I am certainly open to other ideas / strategies, but the intention is to capture a stacktrace when it is actually meaningful. We recently had to chase down an unhandled promise rejection which was rejecting with a null value. This was a very difficult task as --trace-warnings provided no value and essentially required us to instrument our code (including modifying things under node_modules) to an unreasonable level.

So if there is a better way to capture the stack when the rejection actually occurs, and not on the next-tick (when --trace-warnings captures the stack) 👍

@AyushG3112
Copy link
Contributor

Would it make more sense to hide this under a flag? Something like --trace-unhandled-rejections

@BridgeAR
Copy link
Member

I like the general idea about improving this. However, I wonder if this is the right approach in this case. It somewhat mixes two different concerns. I personally feel like it would be best to print a warning in general in case a promise is rejected with a primitive. Some people might want to rely those though, so it could be a bit intrusive for these people. But most people are likely not aware that there is no stack trace in case a primitive is rejected.

@benjamingr @addaleax what do you think about adding a specific option to first opt-in and as a semver-major opt-out to receive a warning with a stack trace in case a promise is rejected with a primitive?

@benjamingr
Copy link
Member

We did this in bluebird in version 2 and removed this behaviour in bluebird 3.

People found this confusing and we ended up removing it.

What we can do however is to create the Error (and not set the reason to it) and to only log it (with the stack trace) by default in our handler without exposing it.

That said - this would require the actual stack context for the unhandled rejection - the code in this PR creates the exception way too late.

I think this might be doable when we get the async-stack-traces API from V8 - but I think it makes sense to do it after your planned logic rewrite with the setImmediate and closure replacing the WeakMap.

@addaleax
Copy link
Member

@benjamingr I think your suggestion is already implementable – the V8 PromiseRejectMessage type has a stack_trace_ property, it just isn’t exposed at this point. And even that might be an oversight, it would be odd for V8 to use Local<> fields if they don’t intend to make it available to API users

@benjamingr
Copy link
Member

@bmeurer can you please confirm that is something you can/want to expose?

@bmeurer
Copy link
Member

bmeurer commented Jun 19, 2018

@benjamingr @addaleax Not sure this was intended to be exposed. @hashseed and @gsathya might know.

@hashseed
Copy link
Member

hashseed commented Jun 20, 2018

This indeed seems to be an oversight and could be added. The stack trace only exists for rejections caused by a thrown exception, and if detailed stack traces were enabled with Isolate::SetCaptureStackTraceForUncaughtExceptions, though.

@benjamingr
Copy link
Member

Ideally Isolate::SetCaptureStackTraceForUncaughtExceptions will be the default in the future - I definitely think there is debugging value in exposing this :)

@benjamingr
Copy link
Member

Hey, this seems to have stalled. @jd-carroll are you interested in exploring the route outlined by Anna here #21372 (comment) ?

@jd-carroll
Copy link
Author

@benjamingr I would love to submit a PR! But i’m a little lost as to where the most appropriate fix would be. Is this something that belongs in the C layer or in Node’s integration with the V8 runtime?

Highly motivated to contribute something meaningful 👍

@benjamingr
Copy link
Member

@hashseed @addaleax would either of you have time to guide @jd-carroll (not urgent) with those changes?

@addaleax
Copy link
Member

@benjamingr @jd-carroll Sure! The first step would be exposing the stack_trace_ field in V8, I think. Most basic information for checking out the V8 source & contributing to it can be found in their wiki, but feel free to let us know if you need any help.

The change itself would look something along the lines of adding a sibling method to the existing ones, e.g. https://github.com/v8/v8/blob/56baf56790de439b3f69e887e94beb3b301ed77c/include/v8.h#L6669

@jasnell
Copy link
Member

jasnell commented Sep 10, 2018

What's the status on this one?

@jasnell jasnell added the stalled Issues and PRs that are stalled. label Sep 10, 2018
@Trott
Copy link
Member

Trott commented Nov 14, 2018

Does someone want to try to get this across the finish line? Or should this be closed?

@nodejs/promises-debugging

@benjamingr
Copy link
Member

Going to close this at the moment, feel free to continue discussion in an issue. Thanks!

@benjamingr benjamingr closed this Jan 21, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
errors Issues and PRs related to JavaScript errors originated in Node.js core. promises Issues and PRs related to ECMAScript promises. stalled Issues and PRs that are stalled.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants