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

errors, child_process: use more internal/errors codes #14998

Closed
wants to merge 15 commits into from

Conversation

maclover7
Copy link
Contributor

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), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • commit message follows commit guidelines
Affected core subsystem(s)

errors, child_process

@nodejs-github-bot nodejs-github-bot added the child_process Issues and PRs related to the child_process subsystem. label Aug 24, 2017
@Trott Trott added semver-major PRs that contain breaking changes and should be released in the next major version. errors Issues and PRs related to JavaScript errors originated in Node.js core. labels Aug 24, 2017
throw new TypeError('Incorrect value of args option');
throw new errors.TypeError('ERR_INVALID_OPT_VALUE',
('arguments[' + pos + ']'),
arguments[pos]);
Copy link
Member

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.

Copy link
Contributor Author

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 😞

Copy link
Member

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?

throw new TypeError('Forked processes must have an IPC channel');
throw new errors.TypeError('ERR_INVALID_OPT_VALUE',
'options.stdio',
options.stdio);
Copy link
Member

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.

@@ -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');
Copy link
Member

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'

Copy link
Contributor Author

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?

Copy link
Member

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);
Copy link
Member

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

Copy link
Member

@jasnell jasnell left a 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

@maclover7
Copy link
Contributor Author

@jasnell PTAL

@BridgeAR
Copy link
Member

Ping @jasnell
This could use some general LGs @nodejs/collaborators

@jasnell
Copy link
Member

jasnell commented Sep 15, 2017

Ping. this needs more @nodejs/tsc review.

@@ -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);
Copy link
Member

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)

<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'
Copy link
Contributor

Choose a reason for hiding this comment

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

child process's

@@ -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 + ']'),
Copy link
Contributor

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.

@@ -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?
Copy link
Contributor

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.

throw new errors.TypeError('ERR_INVALID_OPT_VALUE',
'options.maxBuffer',
maxBuffer);
//'"maxBuffer" must be a positive number');
Copy link
Contributor

Choose a reason for hiding this comment

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

Not needed.

throw new errors.TypeError('ERR_INVALID_OPT_VALUE',
'options.timeout',
timeout);
//"timeout" must be an unsigned integer');
Copy link
Contributor

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; } };
Copy link
Contributor

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);
Copy link
Contributor

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.

@@ -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);
Copy link
Member

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


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);
Copy link
Member

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

@@ -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?
Copy link
Member

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.

}
}


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',
Copy link
Member

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

@BridgeAR
Copy link
Member

Ping @maclover7

@BridgeAR
Copy link
Member

@maclover7 do you still want to pursue this? There is overlapping PR that waits for this one to be merged.

@maclover7
Copy link
Contributor Author

@BridgeAR sorry for my delay -- working on addressing comments. make seems to be taking a little longer lately since lots of changes in master :)

Copy link
Member

@BridgeAR BridgeAR left a 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.

E('ERR_CHILD_PROCESS_IPC_REQUIRED',
'Forked processes must have an IPC channel');
E('ERR_CHILD_PROCESS_STDIO_MAXBUFFER',
(name) => `${name} maxBuffer length exceeded`);
Copy link
Member

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$/;
Copy link
Member

Choose a reason for hiding this comment

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

This should be removed.

@BridgeAR
Copy link
Member

@nodejs/tsc this needs some LGs

@BridgeAR BridgeAR requested a review from a team September 27, 2017 21:48
@joyeecheung
Copy link
Member

@BridgeAR
Copy link
Member

Copy link
Member

@BridgeAR BridgeAR left a 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);
Copy link
Member

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.

Copy link
Member

Choose a reason for hiding this comment

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

@jasnell
Copy link
Member

jasnell commented Oct 30, 2017

@maclover7 ... should this be ready to go ?

@maclover7
Copy link
Contributor Author

rebased, one last CI before landing: https://ci.nodejs.org/job/node-test-pull-request/11783/

@maclover7
Copy link
Contributor Author

New CI after fixing linter error: https://ci.nodejs.org/job/node-test-pull-request/11784/

@@ -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');
Copy link
Member

@apapirovski apapirovski Nov 28, 2017

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].)

@maclover7
Copy link
Contributor Author

maclover7 commented Nov 29, 2017

@apapirovski updated PTAL

@maclover7
Copy link
Contributor Author

Waiting for CI to wrap up: https://ci.nodejs.org/job/node-test-pull-request/11808/

@maclover7 maclover7 self-assigned this Nov 29, 2017
@maclover7
Copy link
Contributor Author

Landing

@maclover7
Copy link
Contributor Author

Landed in b1e6c0d

@maclover7 maclover7 closed this Nov 29, 2017
@maclover7 maclover7 deleted the jm-errors-childprocess branch November 29, 2017 23:57
maclover7 added a commit that referenced this pull request Nov 29, 2017
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
child_process Issues and PRs related to the child_process subsystem. errors Issues and PRs related to JavaScript errors originated in Node.js core. semver-major PRs that contain breaking changes and should be released in the next major version.
Projects
None yet
Development

Successfully merging this pull request may close these issues.