Skip to content

Commit e75bc87

Browse files
committed
errors: port internal/process errors to internal/errors
* Assign codes to the handful of errors reported by internal/process/*.js * Include documentation for the new error codes * Improve error messages * Improve test coverage for process.nextTick PR-URL: #11294 Ref: #11273 Reviewed-By: Michaël Zasso <[email protected]> Reviewed-By: Joyee Cheung <[email protected]> Reviewed-By: Evan Lucas <[email protected]>
1 parent 468275a commit e75bc87

9 files changed

+191
-54
lines changed

doc/api/errors.md

+78-22
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ called.
3636

3737
All JavaScript errors are handled as exceptions that *immediately* generate
3838
and throw an error using the standard JavaScript `throw` mechanism. These
39-
are handled using the [`try / catch` construct][try-catch] provided by the JavaScript
40-
language.
39+
are handled using the [`try / catch` construct][try-catch] provided by the
40+
JavaScript language.
4141

4242
```js
4343
// Throws with a ReferenceError because z is undefined
@@ -105,8 +105,8 @@ pass or fail).
105105

106106
For *all* `EventEmitter` objects, if an `'error'` event handler is not
107107
provided, the error will be thrown, causing the Node.js process to report an
108-
unhandled exception and crash unless either: The [`domain`][domains] module is used
109-
appropriately or a handler has been registered for the
108+
unhandled exception and crash unless either: The [`domain`][domains] module is
109+
used appropriately or a handler has been registered for the
110110
[`process.on('uncaughtException')`][] event.
111111

112112
```js
@@ -255,15 +255,23 @@ will affect any stack trace captured *after* the value has been changed.
255255
If set to a non-number value, or set to a negative number, stack traces will
256256
not capture any frames.
257257

258-
### error.message
258+
#### error.code
259+
260+
* {string}
261+
262+
The `error.code` property is a string label that identifies the kind of error.
263+
See [Node.js Error Codes][] for details about specific codes.
264+
265+
#### error.message
259266

260267
* {string}
261268

262-
The `error.message` property is the string description of the error as set by calling `new Error(message)`.
263-
The `message` passed to the constructor will also appear in the first line of
264-
the stack trace of the `Error`, however changing this property after the
265-
`Error` object is created *may not* change the first line of the stack trace
266-
(for example, when `error.stack` is read before this property is changed).
269+
The `error.message` property is the string description of the error as set by
270+
calling `new Error(message)`. The `message` passed to the constructor will also
271+
appear in the first line of the stack trace of the `Error`, however changing
272+
this property after the `Error` object is created *may not* change the first
273+
line of the stack trace (for example, when `error.stack` is read before this
274+
property is changed).
267275

268276
```js
269277
const err = new Error('The message');
@@ -451,18 +459,18 @@ added properties.
451459

452460
* {string}
453461

454-
The `error.code` property is a string representing the error code, which is always
455-
`E` followed by a sequence of capital letters.
462+
The `error.code` property is a string representing the error code, which is
463+
typically `E` followed by a sequence of capital letters.
456464

457465
#### error.errno
458466

459467
* {string|number}
460468

461469
The `error.errno` property is a number or a string.
462-
The number is a **negative** value which corresponds to the error code defined in
463-
[`libuv Error handling`]. See uv-errno.h header file (`deps/uv/include/uv-errno.h` in
464-
the Node.js source tree) for details.
465-
In case of a string, it is the same as `error.code`.
470+
The number is a **negative** value which corresponds to the error code defined
471+
in [`libuv Error handling`]. See uv-errno.h header file
472+
(`deps/uv/include/uv-errno.h` in the Node.js source tree) for details. In case
473+
of a string, it is the same as `error.code`.
466474

467475
#### error.syscall
468476

@@ -474,22 +482,22 @@ The `error.syscall` property is a string describing the [syscall][] that failed.
474482

475483
* {string}
476484

477-
When present (e.g. in `fs` or `child_process`), the `error.path` property is a string
478-
containing a relevant invalid pathname.
485+
When present (e.g. in `fs` or `child_process`), the `error.path` property is a
486+
string containing a relevant invalid pathname.
479487

480488
#### error.address
481489

482490
* {string}
483491

484-
When present (e.g. in `net` or `dgram`), the `error.address` property is a string
485-
describing the address to which the connection failed.
492+
When present (e.g. in `net` or `dgram`), the `error.address` property is a
493+
string describing the address to which the connection failed.
486494

487495
#### error.port
488496

489497
* {number}
490498

491-
When present (e.g. in `net` or `dgram`), the `error.port` property is a number representing
492-
the connection's port that is not available.
499+
When present (e.g. in `net` or `dgram`), the `error.port` property is a number
500+
representing the connection's port that is not available.
493501

494502
### Common System Errors
495503

@@ -550,6 +558,53 @@ found [here][online].
550558
encountered by [`http`][] or [`net`][] -- often a sign that a `socket.end()`
551559
was not properly called.
552560

561+
<a id="nodejs-error-codes"></a>
562+
## Node.js Error Codes
563+
564+
<a id="ERR_INVALID_ARG_TYPE"></a>
565+
### ERR_INVALID_ARG_TYPE
566+
567+
The `'ERR_INVALID_ARG_TYPE'` error code is used generically to identify that
568+
an argument of the wrong type has been passed to a Node.js API.
569+
570+
<a id="ERR_INVALID_CALLBACK"></a>
571+
### ERR_INVALID_CALLBACK
572+
573+
The `'ERR_INVALID_CALLBACK'` error code is used generically to identify that
574+
a callback function is required and has not been provided to a Node.js API.
575+
576+
<a id="ERR_STDERR_CLOSE"></a>
577+
### ERR_STDERR_CLOSE
578+
579+
An error using the `'ERR_STDERR_CLOSE'` code is thrown specifically when an
580+
attempt is made to close the `process.stderr` stream. By design, Node.js does
581+
not allow `stdout` or `stderr` Streams to be closed by user code.
582+
583+
<a id="ERR_STDOUT_CLOSE"></a>
584+
### ERR_STDOUT_CLOSE
585+
586+
An error using the `'ERR_STDOUT_CLOSE'` code is thrown specifically when an
587+
attempt is made to close the `process.stdout` stream. By design, Node.js does
588+
not allow `stdout` or `stderr` Streams to be closed by user code.
589+
590+
<a id="ERR_UNKNOWN_STDIN_TYPE"></a>
591+
### ERR_UNKNOWN_STDIN_TYPE
592+
593+
An error using the `'ERR_UNKNOWN_STDIN_TYPE'` code is thrown specifically when
594+
an attempt is made to launch a Node.js process with an unknown `stdin` file
595+
type. Errors of this kind cannot *typically* be caused by errors in user code,
596+
although it is not impossible. Occurrences of this error are most likely an
597+
indication of a bug within Node.js itself.
598+
599+
<a id="ERR_UNKNOWN_STREAM_TYPE"></a>
600+
### ERR_UNKNOWN_STREAM_TYPE
601+
602+
An error using the `'ERR_UNKNOWN_STREAM_TYPE'` code is thrown specifically when
603+
an attempt is made to launch a Node.js process with an unknown `stdout` or
604+
`stderr` file type. Errors of this kind cannot *typically* be caused by errors
605+
in user code, although it is not impossible. Occurrences of this error are most
606+
likely an indication of a bug within Node.js itself.
607+
553608
[`fs.readdir`]: fs.html#fs_fs_readdir_path_options_callback
554609
[`fs.readFileSync`]: fs.html#fs_fs_readfilesync_file_options
555610
[`fs.unlink`]: fs.html#fs_fs_unlink_path_callback
@@ -562,6 +617,7 @@ found [here][online].
562617
[domains]: domain.html
563618
[event emitter-based]: events.html#events_class_eventemitter
564619
[file descriptors]: https://en.wikipedia.org/wiki/File_descriptor
620+
[Node.js Error Codes]: #nodejs-error-codes
565621
[online]: http://man7.org/linux/man-pages/man3/errno.3.html
566622
[stream-based]: stream.html
567623
[syscall]: http://man7.org/linux/man-pages/man2/syscall.2.html

lib/internal/errors.js

+28
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,32 @@ module.exports = exports = {
8080
//
8181
// Note: Please try to keep these in alphabetical order
8282
E('ERR_ASSERTION', (msg) => msg);
83+
E('ERR_INVALID_ARG_TYPE', invalidArgType);
84+
E('ERR_INVALID_CALLBACK', 'callback must be a function');
85+
E('ERR_STDERR_CLOSE', 'process.stderr cannot be closed');
86+
E('ERR_STDOUT_CLOSE', 'process.stdout cannot be closed');
87+
E('ERR_UNKNOWN_STDIN_TYPE', 'Unknown stdin file type');
88+
E('ERR_UNKNOWN_STREAM_TYPE', 'Unknown stream file type');
8389
// Add new errors from here...
90+
91+
function invalidArgType(name, expected, actual) {
92+
assert(name, 'name is required');
93+
assert(expected, 'expected is required');
94+
var msg = `The "${name}" argument must be `;
95+
if (Array.isArray(expected)) {
96+
var len = expected.length;
97+
expected = expected.map((i) => String(i));
98+
if (len > 1) {
99+
msg += `one of type ${expected.slice(0, len - 1).join(', ')}, or ` +
100+
expected[len - 1];
101+
} else {
102+
msg += `of type ${expected[0]}`;
103+
}
104+
} else {
105+
msg += `of type ${String(expected)}`;
106+
}
107+
if (arguments.length >= 3) {
108+
msg += `. Received type ${actual !== null ? typeof actual : 'null'}`;
109+
}
110+
return msg;
111+
}

lib/internal/process/next_tick.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ exports.setup = setupNextTick;
1010

1111
function setupNextTick() {
1212
const promises = require('internal/process/promises');
13+
const errors = require('internal/errors');
1314
const emitPendingUnhandledRejections = promises.setup(scheduleMicrotasks);
1415
var nextTickQueue = [];
1516
var microtasksScheduled = false;
@@ -139,7 +140,7 @@ function setupNextTick() {
139140

140141
function nextTick(callback) {
141142
if (typeof callback !== 'function')
142-
throw new TypeError('callback is not a function');
143+
throw new errors.TypeError('ERR_INVALID_CALLBACK');
143144
// on the way out, don't bother. it won't get fired anyway.
144145
if (process._exiting)
145146
return;

lib/internal/process/stdio.js

+19-5
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,25 @@
22

33
exports.setup = setupStdio;
44

5+
var errors;
6+
7+
function lazyErrors() {
8+
if (!errors)
9+
errors = require('internal/errors');
10+
return errors;
11+
}
12+
513
function setupStdio() {
6-
var stdin, stdout, stderr;
14+
var stdin;
15+
var stdout;
16+
var stderr;
717

818
function getStdout() {
919
if (stdout) return stdout;
1020
stdout = createWritableStdioStream(1);
1121
stdout.destroy = stdout.destroySoon = function(er) {
12-
er = er || new Error('process.stdout cannot be closed.');
22+
const errors = lazyErrors();
23+
er = er || new errors.Error('ERR_STDOUT_CLOSE');
1324
stdout.emit('error', er);
1425
};
1526
if (stdout.isTTY) {
@@ -22,7 +33,8 @@ function setupStdio() {
2233
if (stderr) return stderr;
2334
stderr = createWritableStdioStream(2);
2435
stderr.destroy = stderr.destroySoon = function(er) {
25-
er = er || new Error('process.stderr cannot be closed.');
36+
const errors = lazyErrors();
37+
er = er || new errors.Error('ERR_STDERR_CLOSE');
2638
stderr.emit('error', er);
2739
};
2840
if (stderr.isTTY) {
@@ -79,7 +91,8 @@ function setupStdio() {
7991

8092
default:
8193
// Probably an error on in uv_guess_handle()
82-
throw new Error('Implement me. Unknown stdin file type!');
94+
const errors = lazyErrors();
95+
throw new errors.Error('ERR_UNKNOWN_STDIN_TYPE');
8396
}
8497

8598
// For supporting legacy API we put the FD here.
@@ -163,7 +176,8 @@ function createWritableStdioStream(fd) {
163176

164177
default:
165178
// Probably an error on in uv_guess_handle()
166-
throw new Error('Implement me. Unknown stream file type!');
179+
const errors = lazyErrors();
180+
throw new errors.Error('ERR_UNKNOWN_STREAM_TYPE');
167181
}
168182

169183
// For supporting legacy API we put the FD here.

lib/internal/process/warning.js

+12-3
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,18 @@ const prefix = `(${process.release.name}:${process.pid}) `;
55

66
exports.setup = setupProcessWarnings;
77

8+
var errors;
89
var fs;
910
var cachedFd;
1011
var acquiringFd = false;
1112
function nop() {}
1213

14+
function lazyErrors() {
15+
if (!errors)
16+
errors = require('internal/errors');
17+
return errors;
18+
}
19+
1320
function lazyFs() {
1421
if (!fs)
1522
fs = require('fs');
@@ -105,6 +112,7 @@ function setupProcessWarnings() {
105112
// process.emitWarning(error)
106113
// process.emitWarning(str[, type[, code]][, ctor])
107114
process.emitWarning = function(warning, type, code, ctor) {
115+
const errors = lazyErrors();
108116
if (typeof type === 'function') {
109117
ctor = type;
110118
code = undefined;
@@ -115,17 +123,18 @@ function setupProcessWarnings() {
115123
code = undefined;
116124
}
117125
if (code !== undefined && typeof code !== 'string')
118-
throw new TypeError('\'code\' must be a String');
126+
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'code', 'string');
119127
if (type !== undefined && typeof type !== 'string')
120-
throw new TypeError('\'type\' must be a String');
128+
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'type', 'string');
121129
if (warning === undefined || typeof warning === 'string') {
122130
warning = new Error(warning);
123131
warning.name = String(type || 'Warning');
124132
if (code !== undefined) warning.code = code;
125133
Error.captureStackTrace(warning, ctor || process.emitWarning);
126134
}
127135
if (!(warning instanceof Error)) {
128-
throw new TypeError('\'warning\' must be an Error object or string.');
136+
throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
137+
'warning', ['Error', 'string']);
129138
}
130139
if (warning.name === 'DeprecationWarning') {
131140
if (process.noDeprecation)

test/parallel/test-internal-errors.js

+20
Original file line numberDiff line numberDiff line change
@@ -130,3 +130,23 @@ assert.throws(
130130
() => errors.E('TEST_ERROR_USED_SYMBOL'),
131131
/^AssertionError: Error symbol: TEST_ERROR_USED_SYMBOL was already used\.$/
132132
);
133+
134+
// // Test ERR_INVALID_ARG_TYPE
135+
assert.strictEqual(errors.message('ERR_INVALID_ARG_TYPE', ['a', 'b']),
136+
'The "a" argument must be of type b');
137+
assert.strictEqual(errors.message('ERR_INVALID_ARG_TYPE', ['a', ['b']]),
138+
'The "a" argument must be of type b');
139+
assert.strictEqual(errors.message('ERR_INVALID_ARG_TYPE', ['a', ['b', 'c']]),
140+
'The "a" argument must be one of type b, or c');
141+
assert.strictEqual(errors.message('ERR_INVALID_ARG_TYPE',
142+
['a', ['b', 'c', 'd']]),
143+
'The "a" argument must be one of type b, c, or d');
144+
assert.strictEqual(errors.message('ERR_INVALID_ARG_TYPE', ['a', 'b', 'c']),
145+
'The "a" argument must be of type b. Received type string');
146+
assert.strictEqual(errors.message('ERR_INVALID_ARG_TYPE',
147+
['a', 'b', undefined]),
148+
'The "a" argument must be of type b. Received type ' +
149+
'undefined');
150+
assert.strictEqual(errors.message('ERR_INVALID_ARG_TYPE',
151+
['a', 'b', null]),
152+
'The "a" argument must be of type b. Received type null');

test/parallel/test-process-emitwarning.js

+15-12
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,19 @@ warningThrowToString.toString = function() {
3939
};
4040
process.emitWarning(warningThrowToString);
4141

42+
const expectedError =
43+
common.expectsError({code: 'ERR_INVALID_ARG_TYPE', type: TypeError});
44+
4245
// TypeError is thrown on invalid input
43-
assert.throws(() => process.emitWarning(1), TypeError);
44-
assert.throws(() => process.emitWarning({}), TypeError);
45-
assert.throws(() => process.emitWarning(true), TypeError);
46-
assert.throws(() => process.emitWarning([]), TypeError);
47-
assert.throws(() => process.emitWarning('', {}), TypeError);
48-
assert.throws(() => process.emitWarning('', '', {}), TypeError);
49-
assert.throws(() => process.emitWarning('', 1), TypeError);
50-
assert.throws(() => process.emitWarning('', '', 1), TypeError);
51-
assert.throws(() => process.emitWarning('', true), TypeError);
52-
assert.throws(() => process.emitWarning('', '', true), TypeError);
53-
assert.throws(() => process.emitWarning('', []), TypeError);
54-
assert.throws(() => process.emitWarning('', '', []), TypeError);
46+
assert.throws(() => process.emitWarning(1), expectedError);
47+
assert.throws(() => process.emitWarning({}), expectedError);
48+
assert.throws(() => process.emitWarning(true), expectedError);
49+
assert.throws(() => process.emitWarning([]), expectedError);
50+
assert.throws(() => process.emitWarning('', {}), expectedError);
51+
assert.throws(() => process.emitWarning('', '', {}), expectedError);
52+
assert.throws(() => process.emitWarning('', 1), expectedError);
53+
assert.throws(() => process.emitWarning('', '', 1), expectedError);
54+
assert.throws(() => process.emitWarning('', true), expectedError);
55+
assert.throws(() => process.emitWarning('', '', true), expectedError);
56+
assert.throws(() => process.emitWarning('', []), expectedError);
57+
assert.throws(() => process.emitWarning('', '', []), expectedError);

0 commit comments

Comments
 (0)