Status Update
Comments
vi...@chromium.org <vi...@chromium.org> #2
bm...@chromium.org <bm...@chromium.org> #3
bm...@chromium.org <bm...@chromium.org> #4
ma...@chromium.org <ma...@chromium.org> #5
tv...@chromium.org <tv...@chromium.org> #7
bm...@chromium.org <bm...@chromium.org> #8
da...@threema.ch <da...@threema.ch> #9
(I assume the DevTools simply print `Error.stack`, correct?)
bm...@chromium.org <bm...@chromium.org> #10
[Monorail components: -Platform>DevTools>JavaScript Blink>JavaScript]
bm...@chromium.org <bm...@chromium.org> #11
ge...@gmail.com <ge...@gmail.com> #12
bm...@chromium.org <bm...@chromium.org> #13
ge...@gmail.com <ge...@gmail.com> #14
I don't know how Devtools might work, but I would purely guess having that would make the Devtools' ability to display the same quite a bit easier.
If we had the `Error.prototype.stack` including the `cause`s, but Devtools still wasn't showing that info, we could at least much more easily work-around by manually logging the stack property.
So... I guess my answer is "both", but... `Error.prototype.stack` seems more important.
bm...@chromium.org <bm...@chromium.org> #15
s....@gmail.com <s....@gmail.com> #16
I write an array of errors in the "cause" field. For example, there is a list of tasks that must be completed in any case, even if one of them throws an error.
Therefore, it would be convenient for me to see this list of errors at least as a variable that can be saved as a global variable and printed out at my own discretion.
If there are other suggestions for displaying a list of errors, that would be great. But first I would like to see at least the variable from the "cause" field
Display example:
Error: foo
at <anonymous>:1:1
Cause: >[Error, Error]
ya...@google.com <ya...@google.com> #17
je...@gmail.com <je...@gmail.com> #18
sz...@chromium.org <sz...@chromium.org> #19
ha...@google.com <ha...@google.com> #20
is...@google.com <is...@google.com> #21
[Monorail mergedwith:
[Monorail components added to Component Tags custom field.]
vi...@chromium.org <vi...@chromium.org> #22
bm...@google.com <bm...@google.com> #23
This is a V8 issue since Error.stack
is in V8, and the issue is about extending Error.stack
with information about the cause.
vi...@chromium.org <vi...@chromium.org> #24
Okay, but I guess this is not spec'ed. How are we suppose to add this to the stack? What do we add if "cause" is not an error? ToString? How do we chain them?
What do you think, Shu?
ma...@chromium.org <ma...@chromium.org> #25
This is a V8 issue since
Error.stack
is in V8, and the issue is about extendingError.stack
with information about the cause.
For the record, when I filed this issue it was specifically about DevTools support. (Original title: “Support error.cause
in DevTools) That is, displaying an error’s cause when available, similar to what Firefox does when using the example in
I’m not sure how we arrived at instead wanting to extend .stack
, but I’d question if this is the right approach. It doesn’t match the spec nor any existing implementation.
ma...@chromium.org <ma...@chromium.org> #26
I think we can improve tooling support without making observable changes to the platform.
One V8-level change we could consider is using cause
in descriptionForError
(similar to how we’re already using message
if available):
ge...@gmail.com <ge...@gmail.com> #27
It seems natural that there'd be a single-access way to get all known information about the "path" that led to an error. And since that's already what 'stack' is universally understood to be for, I asserted earlier in this thread that's by far more useful than limiting this issue to only a special devtools handling.
There's plenty of use-cases for programmtic handling of error instances which have nothing to do with the devtools console having special behavior to display 'cause'. For example, logging errors (to a log file) from Node, or remote error tracking libraries which send the error info off over the wire to a remote logging service.
All of these use-cases almost certainly access 'stack' already, and thus automatically benefit from 'stack' being extended (appended) with the newly added 'cause' info, without them having to go through the tedious extra work of handling 'cause' separately. None of them benefit from a "devtools only special behavior" approach.
By contrast, the devtools use-case is automatically handled/improved by appending 'cause' to 'stack', since devtools already knows how to access 'stack' and nicely print out its full contents.
This is why I strongly feel the superset behavior (appending 'cause' to 'stack') is the actual useful approach, compared to just a devtools-only limited subset of behavior.
ge...@gmail.com <ge...@gmail.com> #28
I can't think of a single reason anyone using 'stack' would NOT also want/expect 'cause' info (if present).
bm...@google.com <bm...@google.com> #29
I think we need to have the cause printed as part of Error.stack
indeed. Error.stack
is the commonly used way to share call frames..
lo...@gmail.com <lo...@gmail.com> #30
Hey
I'm probably not qualified enough to decide for you.
Just wanted to give some references to how Node.js implemented it as a dev tool feature in Node 16.14:
PR:
The tool they use to log errors to the console: require("node:utils").inspect(error)
By default it does not log the "whole causal chain"
You'd have to explicitly use their API and increase the maximum depth for that: inspect(error, {depth: Infinity})
.
To be honest, this was kind of surprising to me, and I've been bitten by this behavior while trying to use deeply nested error causes inside AggregateError
:
And it seems the info is not attached to the stack attribute and logging the stack does not print the full causal chain either.
> new Error("boom",{cause: new Error("child")})
Error: boom
at REPL3:1:1
at ContextifyScript.runInThisContext (node:vm:121:12)
... 7 lines matching cause stack trace ...
at [_line] [as _line] (node:internal/readline/interface:887:18) {
[cause]: Error: child
at REPL3:1:26
at ContextifyScript.runInThisContext (node:vm:121:12)
at REPLServer.defaultEval (node:repl:599:22)
at bound (node:domain:432:15)
at REPLServer.runBound [as eval] (node:domain:443:12)
at REPLServer.onLine (node:repl:929:10)
at REPLServer.emit (node:events:530:35)
at REPLServer.emit (node:domain:488:12)
at [_onLine] [as _onLine] (node:internal/readline/interface:416:12)
at [_line] [as _line] (node:internal/readline/interface:887:18)
}
> new Error("boom",{cause: new Error("child")}).stack
'Error: boom\n' +
' at REPL9:1:1\n' +
' at ContextifyScript.runInThisContext (node:vm:121:12)\n' +
' at REPLServer.defaultEval (node:repl:599:22)\n' +
' at bound (node:domain:432:15)\n' +
' at REPLServer.runBound [as eval] (node:domain:443:12)\n' +
' at REPLServer.onLine (node:repl:929:10)\n' +
' at REPLServer.emit (node:events:530:35)\n' +
' at REPLServer.emit (node:domain:488:12)\n' +
' at [_onLine] [as _onLine] (node:internal/readline/interface:416:12)\n' +
' at [_line] [as _line] (node:internal/readline/interface:887:18)'
Firefox Nightly shows a similar behavior and does not log the causal chain when logging the parent error.
To me, each error has a different stack trace, so it kind of makes sense to keep them isolated from each other.
However, the most common case is that the parent/child errors would share many stack frames, so the dev tool should rather be able to deduplicate stackframes them to avoid printing them multiple times. (cf how Node.js does it in my example above)
If logging the stack now prints the causal chain too, how could anyone get the "raw" stacktrace anymore, in case they don't want to see/log/report the whole stacktrace but only focus on the stackframes that are related to the current Error? (and not its cause).
That looks to me like a risky change too, some tools might read the stack and now have trouble parsing it.
Another example is how Java does it using nested exceptions:
Exception e = new RuntimeException("Parent error",
new RuntimeException("Child error")
);
System.out.println("getStackTrace : " + java.util.Arrays.toString(e.getStackTrace()));
e.printStackTrace();
getStackTrace : [MyClass.main(MyClass.java:3)]
java.lang.RuntimeException: Parent error
at MyClass.main(MyClass.java:3)
Caused by: java.lang.RuntimeException: Child error
... 1 more
It's possible to get stack frames without the causal chain. However printStackTrace()
will print the causal chain.
ma...@google.com <ma...@google.com> #31
I agree it seems nice to just include the cause
in stack
— but it’s a change that would risk web compat issues, require standardization work, and TC39 stakeholder buy-in before we can proceed. Whoever wants to pursue that has my support.
To help users in the mean time, we could solve it at the V8 Inspector / DevTools level instead, without any platform-observable changes. This matches what Firefox Developer Tools and Node.js do: they helpfully print the cause
whenever an error instance is logged, but avoid messing with .stack
.
bm...@google.com <bm...@google.com> #32
Thanks for the idea. That Node.js approach looks interesting.
ba...@gmail.com <ba...@gmail.com> #33
The stack is already available in full in the cause chain. The problem here is exclusively visualization in the dev tools.
ge...@gmail.com <ge...@gmail.com> #34
No it isn't, as I explained in detail above. :/
bm...@google.com <bm...@google.com> #35
After offline discussion with Mathias, I'm convinced that while it would certainly be useful to include the cause in Error.stack
, the risk of breaking all kinds of assumptions about the shape of Error.stack
produced by V8 is extremely high. So I'm leaning towards the safe option of a DevTools front-end only solution for now.
vi...@chromium.org <vi...@chromium.org> #36
yu...@google.com <yu...@google.com> #37
Is Error.stack
guaranteed not to be updated to include the causal chain? We have some logging infrastructure that currently calls Error.stack
to get the stack trace, and I'm planning to update it to traverse the causal chain and concatenate the stack traces. If Error.stack
were to be updated to include the causal chain, then it would break the logic that I'm planning to implement.
pe...@google.com <pe...@google.com> #38
To update this component's auto-cc rules, visit
go/chrome-blintz-user-guide
da...@gmail.com <da...@gmail.com> #39
would be really nice to see this implemented as our application strictly follows wrapping errors with the cause property. The only way for us to view the cause chain currently is with firefox.
It would be nice to log the entire cause chain in the log however, and not just withing the stack property.
Some log like:
console.error(
new Error("cannot add user", {
cause: new Error("call to /users failed with a 500 status", {
cause: new Error("database call to users table failed")
})
}),
);
should log something like:
Error: cannot add user
at...
[cause]: Error: call to /users failed with a 500 status
at...
[cause]: Error: database call to users table failed
at...
as it would generate fairly large logs, maybe the cause blocks would be dropdowns.
bm...@google.com <bm...@google.com>
ap...@google.com <ap...@google.com> #40
Branch: main
commit 24a5a8e4c30ee75df6a288aadf2911f4bdbdcc0a
Author: Simon Zünd <szuend@chromium.org>
Date: Thu Mar 21 07:28:19 2024
[sdk] Add RemoteError class that wraps a error RemoteObject
Similar to RemoteFunction, we add a RemoteError class that wraps an
JavaScript "Error" object and provides some convinience functions on
top. Namely retrieving the exception details (structured stack trace)
and the "cause".
R=pfaffe@chromium.org
Bug: 40182832
Change-Id: I4c08eec1af8c3326d28497c7591a59059b713123
Reviewed-on:
Reviewed-by: Philip Pfaffe <pfaffe@chromium.org>
Commit-Queue: Simon Zünd <szuend@chromium.org>
M front_end/core/sdk/RemoteObject.test.ts
M front_end/core/sdk/RemoteObject.ts
M front_end/panels/console/ConsoleViewMessage.ts
ap...@google.com <ap...@google.com> #41
Branch: main
commit cf229f3b2820ceda5fcceda045b909ab32bc9660
Author: Simon Zünd <szuend@chromium.org>
Date: Thu Mar 21 07:57:17 2024
[console] Implement basic Error.cause rendering
This CL adds rudimentary support for Error.cause similar to what
firefox is doing. We'll recursively walk the 'cause' chain and print
each errors stack trace with a "Caused by: " prefix.
This CL supports cause objects that are either "Error" objects
themselves or plain strings. A possible improvement could be to
support arbitrary JS objects and call `toString` on them.
We add a simple e2e test to cover the basic user story, aka
"Error.cause works".
R=pfaffe@chromium.org
Fixed: 40182832
Change-Id: I7082e7144b1e6cd9dc20d0409db1e25279780a1d
Reviewed-on:
Commit-Queue: Simon Zünd <szuend@chromium.org>
Reviewed-by: Philip Pfaffe <pfaffe@chromium.org>
M front_end/panels/console/ConsoleViewMessage.ts
M test/e2e/console/console-errors_test.ts
M test/e2e/resources/sources/BUILD.gn
A test/e2e/resources/sources/error-with-cause.html
ap...@google.com <ap...@google.com> #42
Branch: main
commit 6f505129b52effe02d107d621a7eb578a1a2ec42
Author: Philip Pfaffe <pfaffe@chromium.org>
Date: Thu Mar 21 15:42:10 2024
Revert "[console] Implement basic Error.cause rendering"
This reverts commit cf229f3b2820ceda5fcceda045b909ab32bc9660.
Reason for revert: console-eval-blocked-by-CSP_test.ts started flaking after this CL.
Original change's description:
> [console] Implement basic Error.cause rendering
>
> This CL adds rudimentary support for Error.cause similar to what
> firefox is doing. We'll recursively walk the 'cause' chain and print
> each errors stack trace with a "Caused by: " prefix.
>
> This CL supports cause objects that are either "Error" objects
> themselves or plain strings. A possible improvement could be to
> support arbitrary JS objects and call `toString` on them.
>
> We add a simple e2e test to cover the basic user story, aka
> "Error.cause works".
>
> R=pfaffe@chromium.org
>
> Fixed: 40182832
> Change-Id: I7082e7144b1e6cd9dc20d0409db1e25279780a1d
> Reviewed-on:
> Commit-Queue: Simon Zünd <szuend@chromium.org>
> Reviewed-by: Philip Pfaffe <pfaffe@chromium.org>
Bug: 40182832
No-Tree-Checks: true
Change-Id: I356f16a38e15ee38bc82dc4b6cebfec92b93aac2
Reviewed-on:
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Auto-Submit: Philip Pfaffe <pfaffe@chromium.org>
Commit-Queue: Philip Pfaffe <pfaffe@chromium.org>
Reviewed-by: Danil Somsikov <dsv@chromium.org>
Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
M front_end/panels/console/ConsoleViewMessage.ts
M test/e2e/console/console-errors_test.ts
M test/e2e/resources/sources/BUILD.gn
D test/e2e/resources/sources/error-with-cause.html
sz...@google.com <sz...@google.com>
ap...@google.com <ap...@google.com> #43
Branch: main
commit 2e25acd344665f1a7b91303fed549c0c4bfb074e
Author: Simon Zünd <szuend@chromium.org>
Date: Fri Mar 22 07:34:06 2024
Reland "[console] Implement basic Error.cause rendering"
This is a reland of commit cf229f3b2820ceda5fcceda045b909ab32bc9660
The reland includes a fix for a CSP e2e test. Rendering stack traces
has always been asynchronous, but the Error.cause CL makes it worse:
We create the 'div' first and then populate it incrementally and
asynchronously with stack traces.
The CSP e2e test only waited for the 'div' and checked the
div's textContent while we were still building the stack trace.
The fix is to also wait for the stack trace to be present.
Original change's description:
> [console] Implement basic Error.cause rendering
>
> This CL adds rudimentary support for Error.cause similar to what
> firefox is doing. We'll recursively walk the 'cause' chain and print
> each errors stack trace with a "Caused by: " prefix.
>
> This CL supports cause objects that are either "Error" objects
> themselves or plain strings. A possible improvement could be to
> support arbitrary JS objects and call `toString` on them.
>
> We add a simple e2e test to cover the basic user story, aka
> "Error.cause works".
>
> R=pfaffe@chromium.org
>
> Fixed: 40182832
> Change-Id: I7082e7144b1e6cd9dc20d0409db1e25279780a1d
> Reviewed-on:
> Commit-Queue: Simon Zünd <szuend@chromium.org>
> Reviewed-by: Philip Pfaffe <pfaffe@chromium.org>
Fixed: 40182832
Change-Id: I9f9dae16d644cab54794f446d56006861ff322f0
Reviewed-on:
Commit-Queue: Simon Zünd <szuend@chromium.org>
Reviewed-by: Philip Pfaffe <pfaffe@chromium.org>
M front_end/panels/console/ConsoleViewMessage.ts
M test/e2e/console/console-errors_test.ts
M test/e2e/console/console-eval-blocked-by-CSP_test.ts
M test/e2e/resources/sources/BUILD.gn
A test/e2e/resources/sources/error-with-cause.html
Description
```
new Error('foo', { cause: 'bar' });
```
Actual result:
```
Error: foo
at <anonymous>:1:1
```
Expected result would be something like:
```
Error: foo
at <anonymous>:1:1
Cause: …
```