-
Notifications
You must be signed in to change notification settings - Fork 30k
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
errors: make code property mutable #15694
Conversation
ping @jasnell @jdalton @evanlucas |
Is this |
Also I couldn't locate user-facing documentation explaining that |
Here's my take on it: function createClass(Super) {
return class NodeError extends Super {
constructor(key, ...args) {
super(getMessage(key, args))
this[codeSym] = key
}
get code() {
return this[codeSym]
}
set code(value) {
setProperty(this, "code", { value })
}
get name() {
return super.name + " [" + this[codeSym] + "]"
}
set name(value) {
setProperty(this, "name", { value })
}
}
} The Object.defineProperty(this, "code", {
configurable: true,
enumerable: true,
value,
writable: true
}) This way they're still getters until they are overwritten. |
Naïve question perhaps, but what's the benefit of keeping it as a getter? |
Keeps the existing dynamic behavior. I don't have the background on why the getter was used in the first place though. |
Shouldn't |
I suppose so. And probably add a test to confirm that when |
9245993
to
7436ac7
Compare
it looks like we can get rid of the symbol now |
lib/internal/errors.js
Outdated
enumerable: false, | ||
value: `${super.name} [${this[kCode]}]`, | ||
writable: true | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you moved the name
assignment to the prototype it would align with builtin errors
(no-own name prop on error objects).
nix that
Object.defineProperty(NodeError.prototype, 'name', {
configurable: true,
enumerable: false,
value: `${Base.prototype.name} [${this[kCode]}]`,
writable: true
});
return NodeError
Ah, this is why the getter and symbols where used!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Following up on my previous comment.
It looks like getters and a symbol was used to mimic built-in errors which have non-enumerable inherited properties (no-own properties).
So the tweaks needed to the existing errors would be adding setters for code
and name
to assign a value with enumerable
, configurable
, and writable
of true
. To avoid the current chattier console.log
the kCode
symbol assignment could be done with Object.defineProperty
and made enumerable
of false
.
@Trott If you're up for it I could send a PR to your PR, since I'm kind of walking through the code as is and I've never had a commit merged to Node. 😋
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like getters and a symbol was used to mimic built-in errors which have non-enumerable inherited properties (no-own properties).
Yep. That's exactly why
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jdalton are you suggesting to make both makeNodeErr((e) => {
e.name = 'g';
e.code = 'f';
e.message = 'h';
e.toString() === 'g: h';
}); How about keeping |
As mentioned in #15694 (comment), pristine |
Yep. Error objects are created with certain info then thrown to user-land where folks can do what they want with them.
I'm not a fan of obstructing user-land here. My take is that Node creates an error that walks like an error and talks like an error (no own-enumerable properties, standard toString behavior, etc.) and then throws it out. After that it's no longer Node's concern. Folks can catch it, augment it, decorate it, or shallow it. The tweaks to makeNodeError are minimal and the |
@jdalton I have to make one significant change in addition to a few unimportant linting changes. The significant change is to define the I'm leaving |
da94494
to
aa33f44
Compare
That's handled by the var e = new Error("x")
console.log(e.name) // "Error"
console.log(Object.keys(e)) // []
e.name = "foo"
console.log(Object.keys(e)) // ["name"] |
+1 to make the |
@Trott As mentioned in my previous comment, making the console.log(myError.name); // "foo"
delete myError.name
console.log(myError.name) // "Error [ERR_TLS_HANDSHAKE_TIMEOUT]" That removes the own property and goes back to the prototypal property. |
My only concern is 3rd party unintentional clobbering. I'd rather we make it a tiny bit hard for libraries to completely clobber the new behaviour. So can we think of a way to get to the code even if |
lib/internal/errors.js
Outdated
set name(value) { | ||
defineProperty(this, 'name', { | ||
configurable: true, | ||
enumerable: false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Likely should be true after setting.
It kinda looks like you're in a bad testing state somehow @Trott. Could the test be running with |
@jdalton I'm not seeing it anymore either even after I roll back the last commit I just added. I must have gotten confused about what binary corresponded to what code changes and been running a binary against an earlier version of this PR. Sorry about the unproductive detour. |
@jdalton I'll split out the |
For internal errors, make `code` and `name` settable while keeping them non-own properties by default. Fixes: nodejs#15658
CI looks good. (OS X failure is infra issues and unrelated.) |
Userland code can break if it depends on a mutable `code` property for errors. Allow users to change the `code` property but do not propagate changes to the error `name`. Additionally, make `message` and `name` consistent with `Error` object (non-enumerable). Test that `console.log()` and `.toString()` calls on internal `Error` objects with mutated properties have analogous results with the standard ECMAScript `Error` objects. PR-URL: nodejs#15694 Fixes: nodejs#15658 Reviewed-By: Evan Lucas <evanlucas@me.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
For internal errors, make `code` and `name` settable while keeping them non-own properties by default. PR-URL: nodejs#15694 Fixes: nodejs#15658 Reviewed-By: Evan Lucas <evanlucas@me.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
This is not landing cleanly on 8.x, could you please send a backport. |
Added the |
@MylesBorins Backport in #16078 |
Userland code can break if it depends on a mutable `code` property for errors. Allow users to change the `code` property but do not propagate changes to the error `name`. Additionally, make `message` and `name` consistent with `Error` object (non-enumerable). Test that `console.log()` and `.toString()` calls on internal `Error` objects with mutated properties have analogous results with the standard ECMAScript `Error` objects. PR-URL: nodejs/node#15694 Fixes: nodejs/node#15658 Reviewed-By: Evan Lucas <evanlucas@me.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
For internal errors, make `code` and `name` settable while keeping them non-own properties by default. PR-URL: nodejs/node#15694 Fixes: nodejs/node#15658 Reviewed-By: Evan Lucas <evanlucas@me.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Userland code can break if it depends on a mutable `code` property for errors. Allow users to change the `code` property but do not propagate changes to the error `name`. Additionally, make `message` and `name` consistent with `Error` object (non-enumerable). Test that `console.log()` and `.toString()` calls on internal `Error` objects with mutated properties have analogous results with the standard ECMAScript `Error` objects. PR-URL: nodejs#15694 Fixes: nodejs#15658 Reviewed-By: Evan Lucas <evanlucas@me.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
For internal errors, make `code` and `name` settable while keeping them non-own properties by default. PR-URL: nodejs#15694 Fixes: nodejs#15658 Reviewed-By: Evan Lucas <evanlucas@me.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Userland code can break if it depends on a mutable `code` property for errors. Allow users to change the `code` property but do not propagate changes to the error `name`. Additionally, make `message` and `name` consistent with `Error` object (non-enumerable). Test that `console.log()` and `.toString()` calls on internal `Error` objects with mutated properties have analogous results with the standard ECMAScript `Error` objects. Backport-PR-URL: #16078 PR-URL: #15694 Fixes: #15658 Reviewed-By: Evan Lucas <evanlucas@me.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
For internal errors, make `code` and `name` settable while keeping them non-own properties by default. Backport-PR-URL: #16078 PR-URL: #15694 Fixes: #15658 Reviewed-By: Evan Lucas <evanlucas@me.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Userland code can break if it depends on a mutable
code
property forerrors. Allow users to change the
code
property but do not propagatechanges to the error
name
.Additionally, make
message
andname
consistent withError
object(non-enumerable). Test that
console.log()
and.toString()
calls oninternal
Error
objects with mutated properties have analogous resultswith the standard ECMAScript
Error
objects.Fixes: #15658
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
errors