-
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, child_process: use more internal/errors codes #14998
Conversation
lib/child_process.js
Outdated
throw new TypeError('Incorrect value of args option'); | ||
throw new errors.TypeError('ERR_INVALID_OPT_VALUE', | ||
('arguments[' + pos + ']'), | ||
arguments[pos]); |
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.
This one feels super odd to me... will think about this a bit more.
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.
Felt odd to me too, and still mulling over how to properly present this state to users 😞
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.
Shouldn't this be a ERR_INVALID_ARG_TYPE
though? Judging from the code below I would say it's options
that has the wrong type?
lib/child_process.js
Outdated
throw new TypeError('Forked processes must have an IPC channel'); | ||
throw new errors.TypeError('ERR_INVALID_OPT_VALUE', | ||
'options.stdio', | ||
options.stdio); |
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.
I think a more specific error is better for this.
e.g. new errors.Error('ERR_CHILD_PROCESS_IPC_REQUIRED')
with the original error message in tact.
lib/child_process.js
Outdated
@@ -318,6 +323,8 @@ exports.execFile = function(file /*, args, options, callback*/) { | |||
stdoutLen += encoding ? Buffer.byteLength(chunk, encoding) : chunk.length; | |||
|
|||
if (stdoutLen > options.maxBuffer) { | |||
// TODO helpful to convert to ERR_BUFFER_OUT_OF_BOUNDS? | |||
// can't specify stderr/stdout with that new error. | |||
ex = new Error('stdout maxBuffer exceeded'); |
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.
I would make this a RangeError
with a specific (slightly improved) error message... e.g.
new errors.RangeError('ERR_CHILD_PROCESS_STDOUT_MAXBUFFER') // 'stdout maxBuffer length exceeded'
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.
Would have to create ERR_CHILD_PROCESS_STDERR_MAXBUFFER
in addition to ERR_CHILD_PROCESS_STDOUT_MAXBUFFER
, is this ok?
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.
Or create a single ERR_CHILD_PROCESS_STDIO_MAXBUFFER that takes a single argument specifying 'stdout' or 'stderr'
const expectedError = | ||
common.expectsError({ code: 'ERR_INVALID_OPT_VALUE', type: TypeError }); | ||
|
||
assert.throws(() => fork(childScript, malFormedOpts), expectedError); |
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's now possible to combine these into ...
common.expectsError(() => fork(...), { code: 'ERR_INVALID_OPT_VALUE', type: TypeError });
etc
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.
This is definitely heading in the right direction! Thank you so very much! I've left a few comments and will do another thorough review a bit later
@jasnell PTAL |
Ping @jasnell |
Ping. this needs more @nodejs/tsc review. |
lib/child_process.js
Outdated
@@ -192,7 +197,7 @@ exports.execFile = function(file /*, args, options, callback*/) { | |||
} | |||
|
|||
if (!callback && pos < arguments.length && arguments[pos] != null) { | |||
throw new TypeError('Incorrect value of args option'); | |||
throw new errors.TypeError('ERR_INVALID_OPT_VALUE', 'args', arguments); |
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.
IIUC the error message would be The value "['file', [], '']" is invalid for option "args"
if we do execFile('file', [], '')
, but then those are all the arguments, not args
(which is []
in this case)
doc/api/errors.md
Outdated
<a id="ERR_CHILD_PROCESS_STDIO_MAXBUFFER"></a> | ||
### ERR_CHILD_PROCESS_STDIO_MAXBUFFER | ||
|
||
Used when the main process is trying to read data from the child process' |
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.
child process's
lib/child_process.js
Outdated
@@ -61,7 +62,9 @@ exports.fork = function(modulePath /*, args, options*/) { | |||
|
|||
if (pos < arguments.length && arguments[pos] != null) { | |||
if (typeof arguments[pos] !== 'object') { | |||
throw new TypeError('Incorrect value of args option'); | |||
throw new errors.TypeError('ERR_INVALID_OPT_VALUE', | |||
('arguments[' + pos + ']'), |
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.
Nit: A template literal would be better here I guess.
lib/child_process.js
Outdated
@@ -612,14 +643,22 @@ exports.execSync = execSync; | |||
|
|||
function validateTimeout(timeout) { | |||
if (timeout != null && !(Number.isInteger(timeout) && timeout >= 0)) { | |||
throw new TypeError('"timeout" must be an unsigned integer'); | |||
// TODO should this be a RangeError? |
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.
The old error message seems okay to me.
lib/child_process.js
Outdated
throw new errors.TypeError('ERR_INVALID_OPT_VALUE', | ||
'options.maxBuffer', | ||
maxBuffer); | ||
//'"maxBuffer" must be a positive number'); |
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.
Not needed.
lib/child_process.js
Outdated
throw new errors.TypeError('ERR_INVALID_OPT_VALUE', | ||
'options.timeout', | ||
timeout); | ||
//"timeout" must be an unsigned integer'); |
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.
Not needed.
|
||
assert.throws(function() { | ||
const file = { toString() { throw new Error('foo'); } }; | ||
const file = { toString() { return null; } }; |
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.
Is this intentional? What happens now if the error is thrown like in the old test?
|
||
common.expectsError( | ||
() => spawnSync('cat', [], options), | ||
{ code: 'ERR_INVALID_ARG_TYPE', type: TypeError }, 1); |
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.
Just making an observation. This is the only place in this patch where expectsError
is explicitly passed 1
.
lib/child_process.js
Outdated
@@ -375,13 +382,13 @@ function _convertCustomFds(options) { | |||
|
|||
function normalizeSpawnArguments(file, args, options) { | |||
if (typeof file !== 'string' || file.length === 0) | |||
throw new TypeError('"file" argument must be a non-empty string'); | |||
throw new errors.TypeError('ERR_INVALID_OPT_VALUE', 'file', file); |
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.
This should be ERR_INVALID_ARG_TYPE
lib/child_process.js
Outdated
|
||
if (Array.isArray(args)) { | ||
args = args.slice(0); | ||
} else if (args !== undefined && | ||
(args === null || typeof args !== 'object')) { | ||
throw new TypeError('Incorrect value of args option'); | ||
throw new errors.TypeError('ERR_INVALID_OPT_VALUE', 'args', args); |
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.
This should be ERR_INVALID_ARG_TYPE
lib/child_process.js
Outdated
@@ -612,14 +643,22 @@ exports.execSync = execSync; | |||
|
|||
function validateTimeout(timeout) { | |||
if (timeout != null && !(Number.isInteger(timeout) && timeout >= 0)) { | |||
throw new TypeError('"timeout" must be an unsigned integer'); | |||
// TODO should this be a RangeError? |
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.
Yeah...I think this should be a RangeError
.
lib/child_process.js
Outdated
} | ||
} | ||
|
||
|
||
function validateMaxBuffer(maxBuffer) { | ||
if (maxBuffer != null && !(typeof maxBuffer === 'number' && maxBuffer >= 0)) { | ||
throw new TypeError('"maxBuffer" must be a positive number'); | ||
// TODO should this be a RangeError? | ||
throw new errors.TypeError('ERR_INVALID_OPT_VALUE', |
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.
This is a RangeError
as well
Ping @maclover7 |
@maclover7 do you still want to pursue this? There is overlapping PR that waits for this one to be merged. |
@BridgeAR sorry for my delay -- working on addressing comments. |
6f1c996
to
601549a
Compare
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.
Overall LGTM but the the commented code should be removed.
lib/internal/errors.js
Outdated
E('ERR_CHILD_PROCESS_IPC_REQUIRED', | ||
'Forked processes must have an IPC channel'); | ||
E('ERR_CHILD_PROCESS_STDIO_MAXBUFFER', | ||
(name) => `${name} maxBuffer length exceeded`); |
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.
Nit - to keep it consistent with the other types it should use %s maxBuffer length exceeded
. That is not blocking though.
} | ||
|
||
{ | ||
// Validate the maxBuffer option | ||
const err = /^TypeError: "maxBuffer" must be a positive number$/; | ||
//const err = /^TypeError: "maxBuffer" must be a positive number$/; |
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.
This should be removed.
@nodejs/tsc this needs some LGs |
Rerun of the CI https://ci.nodejs.org/job/node-test-pull-request/10304/ |
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.
LGTM and this is ready to land besides the failing Windows test.
@@ -4,6 +4,12 @@ const assert = require('assert'); | |||
const spawnSync = require('child_process').spawnSync; | |||
const signals = process.binding('constants').os.signals; | |||
|
|||
const invalidArgTypeError = | |||
common.expectsError({ code: 'ERR_INVALID_ARG_TYPE', type: TypeError }, 56); |
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.
On Windows there are only 36 entries because a couple tests are not run on Windows.
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.
@maclover7 ... should this be ready to go ? |
a5ee4d8
to
17e304d
Compare
rebased, one last CI before landing: https://ci.nodejs.org/job/node-test-pull-request/11783/ |
New CI after fixing linter error: https://ci.nodejs.org/job/node-test-pull-request/11784/ |
lib/internal/errors.js
Outdated
@@ -272,6 +272,9 @@ E('ERR_BUFFER_TOO_LARGE', | |||
`Cannot create a Buffer larger than 0x${kMaxLength.toString(16)} bytes`); | |||
E('ERR_CANNOT_WATCH_SIGINT', 'Cannot watch for SIGINT signals'); | |||
E('ERR_CHILD_CLOSED_BEFORE_REPLY', 'Child closed before reply received'); | |||
E('ERR_CHILD_PROCESS_IPC_REQUIRED', | |||
'Forked processes must have an IPC channel, %s is %s'); |
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.
This is used in one place, it doesn't feel like %s is %s
is really that helpful. It should probably just say something like Forked processes must have an IPC channel, missing value 'ipc' in %s
.
(This accepts an array so the %s
would be [value, value, value]
.)
@apapirovski updated PTAL |
Waiting for CI to wrap up: https://ci.nodejs.org/job/node-test-pull-request/11808/ |
Landing |
Landed in b1e6c0d |
PR-URL: #14998 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Stephen Belanger <admin@stephenbelanger.com> Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
Converts more (I believe this is all that is remaining?) of
child_process
to new-errors
-land. Most of this diff is straight copy and replace, so I don't think it's too intimidating. There are a few TODOs left in this PR on purpose that require some discussion, so I would appreciate any feedback on those.Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
errors, child_process