summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames M Snell <jasnell@gmail.com>2017-02-10 08:51:50 -0800
committerJames M Snell <jasnell@gmail.com>2017-04-20 11:34:07 -0700
commite75bc87d2240097ddf4074c473b4ea946daf390d (patch)
treeed03f175a3efe6ed40ee30e96131f73c81734f7b
parent468275ac7911b3f7950f31e9799b6666c96f2c73 (diff)
downloadandroid-node-v8-e75bc87d2240097ddf4074c473b4ea946daf390d.tar.gz
android-node-v8-e75bc87d2240097ddf4074c473b4ea946daf390d.tar.bz2
android-node-v8-e75bc87d2240097ddf4074c473b4ea946daf390d.zip
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: https://github.com/nodejs/node/pull/11294 Ref: https://github.com/nodejs/node/issues/11273 Reviewed-By: Michaƫl Zasso <targos@protonmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Evan Lucas <evanlucas@me.com>
-rw-r--r--doc/api/errors.md100
-rw-r--r--lib/internal/errors.js28
-rw-r--r--lib/internal/process/next_tick.js3
-rw-r--r--lib/internal/process/stdio.js24
-rw-r--r--lib/internal/process/warning.js15
-rw-r--r--test/parallel/test-internal-errors.js20
-rw-r--r--test/parallel/test-process-emitwarning.js27
-rw-r--r--test/parallel/test-process-next-tick.js10
-rw-r--r--test/pseudo-tty/test-tty-stdout-end.js18
9 files changed, 191 insertions, 54 deletions
diff --git a/doc/api/errors.md b/doc/api/errors.md
index 05758cf20b..7ee2963ae0 100644
--- a/doc/api/errors.md
+++ b/doc/api/errors.md
@@ -36,8 +36,8 @@ called.
All JavaScript errors are handled as exceptions that *immediately* generate
and throw an error using the standard JavaScript `throw` mechanism. These
-are handled using the [`try / catch` construct][try-catch] provided by the JavaScript
-language.
+are handled using the [`try / catch` construct][try-catch] provided by the
+JavaScript language.
```js
// Throws with a ReferenceError because z is undefined
@@ -105,8 +105,8 @@ pass or fail).
For *all* `EventEmitter` objects, if an `'error'` event handler is not
provided, the error will be thrown, causing the Node.js process to report an
-unhandled exception and crash unless either: The [`domain`][domains] module is used
-appropriately or a handler has been registered for the
+unhandled exception and crash unless either: The [`domain`][domains] module is
+used appropriately or a handler has been registered for the
[`process.on('uncaughtException')`][] event.
```js
@@ -255,15 +255,23 @@ will affect any stack trace captured *after* the value has been changed.
If set to a non-number value, or set to a negative number, stack traces will
not capture any frames.
-### error.message
+#### error.code
+
+* {string}
+
+The `error.code` property is a string label that identifies the kind of error.
+See [Node.js Error Codes][] for details about specific codes.
+
+#### error.message
* {string}
-The `error.message` property is the string description of the error as set by calling `new Error(message)`.
-The `message` passed to the constructor will also appear in the first line of
-the stack trace of the `Error`, however changing this property after the
-`Error` object is created *may not* change the first line of the stack trace
-(for example, when `error.stack` is read before this property is changed).
+The `error.message` property is the string description of the error as set by
+calling `new Error(message)`. The `message` passed to the constructor will also
+appear in the first line of the stack trace of the `Error`, however changing
+this property after the `Error` object is created *may not* change the first
+line of the stack trace (for example, when `error.stack` is read before this
+property is changed).
```js
const err = new Error('The message');
@@ -451,18 +459,18 @@ added properties.
* {string}
-The `error.code` property is a string representing the error code, which is always
-`E` followed by a sequence of capital letters.
+The `error.code` property is a string representing the error code, which is
+typically `E` followed by a sequence of capital letters.
#### error.errno
* {string|number}
The `error.errno` property is a number or a string.
-The number is a **negative** value which corresponds to the error code defined in
-[`libuv Error handling`]. See uv-errno.h header file (`deps/uv/include/uv-errno.h` in
-the Node.js source tree) for details.
-In case of a string, it is the same as `error.code`.
+The number is a **negative** value which corresponds to the error code defined
+in [`libuv Error handling`]. See uv-errno.h header file
+(`deps/uv/include/uv-errno.h` in the Node.js source tree) for details. In case
+of a string, it is the same as `error.code`.
#### error.syscall
@@ -474,22 +482,22 @@ The `error.syscall` property is a string describing the [syscall][] that failed.
* {string}
-When present (e.g. in `fs` or `child_process`), the `error.path` property is a string
-containing a relevant invalid pathname.
+When present (e.g. in `fs` or `child_process`), the `error.path` property is a
+string containing a relevant invalid pathname.
#### error.address
* {string}
-When present (e.g. in `net` or `dgram`), the `error.address` property is a string
-describing the address to which the connection failed.
+When present (e.g. in `net` or `dgram`), the `error.address` property is a
+string describing the address to which the connection failed.
#### error.port
* {number}
-When present (e.g. in `net` or `dgram`), the `error.port` property is a number representing
-the connection's port that is not available.
+When present (e.g. in `net` or `dgram`), the `error.port` property is a number
+representing the connection's port that is not available.
### Common System Errors
@@ -550,6 +558,53 @@ found [here][online].
encountered by [`http`][] or [`net`][] -- often a sign that a `socket.end()`
was not properly called.
+<a id="nodejs-error-codes"></a>
+## Node.js Error Codes
+
+<a id="ERR_INVALID_ARG_TYPE"></a>
+### ERR_INVALID_ARG_TYPE
+
+The `'ERR_INVALID_ARG_TYPE'` error code is used generically to identify that
+an argument of the wrong type has been passed to a Node.js API.
+
+<a id="ERR_INVALID_CALLBACK"></a>
+### ERR_INVALID_CALLBACK
+
+The `'ERR_INVALID_CALLBACK'` error code is used generically to identify that
+a callback function is required and has not been provided to a Node.js API.
+
+<a id="ERR_STDERR_CLOSE"></a>
+### ERR_STDERR_CLOSE
+
+An error using the `'ERR_STDERR_CLOSE'` code is thrown specifically when an
+attempt is made to close the `process.stderr` stream. By design, Node.js does
+not allow `stdout` or `stderr` Streams to be closed by user code.
+
+<a id="ERR_STDOUT_CLOSE"></a>
+### ERR_STDOUT_CLOSE
+
+An error using the `'ERR_STDOUT_CLOSE'` code is thrown specifically when an
+attempt is made to close the `process.stdout` stream. By design, Node.js does
+not allow `stdout` or `stderr` Streams to be closed by user code.
+
+<a id="ERR_UNKNOWN_STDIN_TYPE"></a>
+### ERR_UNKNOWN_STDIN_TYPE
+
+An error using the `'ERR_UNKNOWN_STDIN_TYPE'` code is thrown specifically when
+an attempt is made to launch a Node.js process with an unknown `stdin` file
+type. Errors of this kind cannot *typically* be caused by errors in user code,
+although it is not impossible. Occurrences of this error are most likely an
+indication of a bug within Node.js itself.
+
+<a id="ERR_UNKNOWN_STREAM_TYPE"></a>
+### ERR_UNKNOWN_STREAM_TYPE
+
+An error using the `'ERR_UNKNOWN_STREAM_TYPE'` code is thrown specifically when
+an attempt is made to launch a Node.js process with an unknown `stdout` or
+`stderr` file type. Errors of this kind cannot *typically* be caused by errors
+in user code, although it is not impossible. Occurrences of this error are most
+likely an indication of a bug within Node.js itself.
+
[`fs.readdir`]: fs.html#fs_fs_readdir_path_options_callback
[`fs.readFileSync`]: fs.html#fs_fs_readfilesync_file_options
[`fs.unlink`]: fs.html#fs_fs_unlink_path_callback
@@ -562,6 +617,7 @@ found [here][online].
[domains]: domain.html
[event emitter-based]: events.html#events_class_eventemitter
[file descriptors]: https://en.wikipedia.org/wiki/File_descriptor
+[Node.js Error Codes]: #nodejs-error-codes
[online]: http://man7.org/linux/man-pages/man3/errno.3.html
[stream-based]: stream.html
[syscall]: http://man7.org/linux/man-pages/man2/syscall.2.html
diff --git a/lib/internal/errors.js b/lib/internal/errors.js
index aa3bb0de1d..dc56c68f34 100644
--- a/lib/internal/errors.js
+++ b/lib/internal/errors.js
@@ -80,4 +80,32 @@ module.exports = exports = {
//
// Note: Please try to keep these in alphabetical order
E('ERR_ASSERTION', (msg) => msg);
+E('ERR_INVALID_ARG_TYPE', invalidArgType);
+E('ERR_INVALID_CALLBACK', 'callback must be a function');
+E('ERR_STDERR_CLOSE', 'process.stderr cannot be closed');
+E('ERR_STDOUT_CLOSE', 'process.stdout cannot be closed');
+E('ERR_UNKNOWN_STDIN_TYPE', 'Unknown stdin file type');
+E('ERR_UNKNOWN_STREAM_TYPE', 'Unknown stream file type');
// Add new errors from here...
+
+function invalidArgType(name, expected, actual) {
+ assert(name, 'name is required');
+ assert(expected, 'expected is required');
+ var msg = `The "${name}" argument must be `;
+ if (Array.isArray(expected)) {
+ var len = expected.length;
+ expected = expected.map((i) => String(i));
+ if (len > 1) {
+ msg += `one of type ${expected.slice(0, len - 1).join(', ')}, or ` +
+ expected[len - 1];
+ } else {
+ msg += `of type ${expected[0]}`;
+ }
+ } else {
+ msg += `of type ${String(expected)}`;
+ }
+ if (arguments.length >= 3) {
+ msg += `. Received type ${actual !== null ? typeof actual : 'null'}`;
+ }
+ return msg;
+}
diff --git a/lib/internal/process/next_tick.js b/lib/internal/process/next_tick.js
index ad635aaf49..c834ffc2e3 100644
--- a/lib/internal/process/next_tick.js
+++ b/lib/internal/process/next_tick.js
@@ -10,6 +10,7 @@ exports.setup = setupNextTick;
function setupNextTick() {
const promises = require('internal/process/promises');
+ const errors = require('internal/errors');
const emitPendingUnhandledRejections = promises.setup(scheduleMicrotasks);
var nextTickQueue = [];
var microtasksScheduled = false;
@@ -139,7 +140,7 @@ function setupNextTick() {
function nextTick(callback) {
if (typeof callback !== 'function')
- throw new TypeError('callback is not a function');
+ throw new errors.TypeError('ERR_INVALID_CALLBACK');
// on the way out, don't bother. it won't get fired anyway.
if (process._exiting)
return;
diff --git a/lib/internal/process/stdio.js b/lib/internal/process/stdio.js
index cf69657e40..b6c866e194 100644
--- a/lib/internal/process/stdio.js
+++ b/lib/internal/process/stdio.js
@@ -2,14 +2,25 @@
exports.setup = setupStdio;
+var errors;
+
+function lazyErrors() {
+ if (!errors)
+ errors = require('internal/errors');
+ return errors;
+}
+
function setupStdio() {
- var stdin, stdout, stderr;
+ var stdin;
+ var stdout;
+ var stderr;
function getStdout() {
if (stdout) return stdout;
stdout = createWritableStdioStream(1);
stdout.destroy = stdout.destroySoon = function(er) {
- er = er || new Error('process.stdout cannot be closed.');
+ const errors = lazyErrors();
+ er = er || new errors.Error('ERR_STDOUT_CLOSE');
stdout.emit('error', er);
};
if (stdout.isTTY) {
@@ -22,7 +33,8 @@ function setupStdio() {
if (stderr) return stderr;
stderr = createWritableStdioStream(2);
stderr.destroy = stderr.destroySoon = function(er) {
- er = er || new Error('process.stderr cannot be closed.');
+ const errors = lazyErrors();
+ er = er || new errors.Error('ERR_STDERR_CLOSE');
stderr.emit('error', er);
};
if (stderr.isTTY) {
@@ -79,7 +91,8 @@ function setupStdio() {
default:
// Probably an error on in uv_guess_handle()
- throw new Error('Implement me. Unknown stdin file type!');
+ const errors = lazyErrors();
+ throw new errors.Error('ERR_UNKNOWN_STDIN_TYPE');
}
// For supporting legacy API we put the FD here.
@@ -163,7 +176,8 @@ function createWritableStdioStream(fd) {
default:
// Probably an error on in uv_guess_handle()
- throw new Error('Implement me. Unknown stream file type!');
+ const errors = lazyErrors();
+ throw new errors.Error('ERR_UNKNOWN_STREAM_TYPE');
}
// For supporting legacy API we put the FD here.
diff --git a/lib/internal/process/warning.js b/lib/internal/process/warning.js
index bf487f38a4..86fe491e57 100644
--- a/lib/internal/process/warning.js
+++ b/lib/internal/process/warning.js
@@ -5,11 +5,18 @@ const prefix = `(${process.release.name}:${process.pid}) `;
exports.setup = setupProcessWarnings;
+var errors;
var fs;
var cachedFd;
var acquiringFd = false;
function nop() {}
+function lazyErrors() {
+ if (!errors)
+ errors = require('internal/errors');
+ return errors;
+}
+
function lazyFs() {
if (!fs)
fs = require('fs');
@@ -105,6 +112,7 @@ function setupProcessWarnings() {
// process.emitWarning(error)
// process.emitWarning(str[, type[, code]][, ctor])
process.emitWarning = function(warning, type, code, ctor) {
+ const errors = lazyErrors();
if (typeof type === 'function') {
ctor = type;
code = undefined;
@@ -115,9 +123,9 @@ function setupProcessWarnings() {
code = undefined;
}
if (code !== undefined && typeof code !== 'string')
- throw new TypeError('\'code\' must be a String');
+ throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'code', 'string');
if (type !== undefined && typeof type !== 'string')
- throw new TypeError('\'type\' must be a String');
+ throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'type', 'string');
if (warning === undefined || typeof warning === 'string') {
warning = new Error(warning);
warning.name = String(type || 'Warning');
@@ -125,7 +133,8 @@ function setupProcessWarnings() {
Error.captureStackTrace(warning, ctor || process.emitWarning);
}
if (!(warning instanceof Error)) {
- throw new TypeError('\'warning\' must be an Error object or string.');
+ throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
+ 'warning', ['Error', 'string']);
}
if (warning.name === 'DeprecationWarning') {
if (process.noDeprecation)
diff --git a/test/parallel/test-internal-errors.js b/test/parallel/test-internal-errors.js
index b43d825e6c..fbd627b030 100644
--- a/test/parallel/test-internal-errors.js
+++ b/test/parallel/test-internal-errors.js
@@ -130,3 +130,23 @@ assert.throws(
() => errors.E('TEST_ERROR_USED_SYMBOL'),
/^AssertionError: Error symbol: TEST_ERROR_USED_SYMBOL was already used\.$/
);
+
+// // Test ERR_INVALID_ARG_TYPE
+assert.strictEqual(errors.message('ERR_INVALID_ARG_TYPE', ['a', 'b']),
+ 'The "a" argument must be of type b');
+assert.strictEqual(errors.message('ERR_INVALID_ARG_TYPE', ['a', ['b']]),
+ 'The "a" argument must be of type b');
+assert.strictEqual(errors.message('ERR_INVALID_ARG_TYPE', ['a', ['b', 'c']]),
+ 'The "a" argument must be one of type b, or c');
+assert.strictEqual(errors.message('ERR_INVALID_ARG_TYPE',
+ ['a', ['b', 'c', 'd']]),
+ 'The "a" argument must be one of type b, c, or d');
+assert.strictEqual(errors.message('ERR_INVALID_ARG_TYPE', ['a', 'b', 'c']),
+ 'The "a" argument must be of type b. Received type string');
+assert.strictEqual(errors.message('ERR_INVALID_ARG_TYPE',
+ ['a', 'b', undefined]),
+ 'The "a" argument must be of type b. Received type ' +
+ 'undefined');
+assert.strictEqual(errors.message('ERR_INVALID_ARG_TYPE',
+ ['a', 'b', null]),
+ 'The "a" argument must be of type b. Received type null');
diff --git a/test/parallel/test-process-emitwarning.js b/test/parallel/test-process-emitwarning.js
index b749100001..bebdc989a2 100644
--- a/test/parallel/test-process-emitwarning.js
+++ b/test/parallel/test-process-emitwarning.js
@@ -39,16 +39,19 @@ warningThrowToString.toString = function() {
};
process.emitWarning(warningThrowToString);
+const expectedError =
+ common.expectsError({code: 'ERR_INVALID_ARG_TYPE', type: TypeError});
+
// TypeError is thrown on invalid input
-assert.throws(() => process.emitWarning(1), TypeError);
-assert.throws(() => process.emitWarning({}), TypeError);
-assert.throws(() => process.emitWarning(true), TypeError);
-assert.throws(() => process.emitWarning([]), TypeError);
-assert.throws(() => process.emitWarning('', {}), TypeError);
-assert.throws(() => process.emitWarning('', '', {}), TypeError);
-assert.throws(() => process.emitWarning('', 1), TypeError);
-assert.throws(() => process.emitWarning('', '', 1), TypeError);
-assert.throws(() => process.emitWarning('', true), TypeError);
-assert.throws(() => process.emitWarning('', '', true), TypeError);
-assert.throws(() => process.emitWarning('', []), TypeError);
-assert.throws(() => process.emitWarning('', '', []), TypeError);
+assert.throws(() => process.emitWarning(1), expectedError);
+assert.throws(() => process.emitWarning({}), expectedError);
+assert.throws(() => process.emitWarning(true), expectedError);
+assert.throws(() => process.emitWarning([]), expectedError);
+assert.throws(() => process.emitWarning('', {}), expectedError);
+assert.throws(() => process.emitWarning('', '', {}), expectedError);
+assert.throws(() => process.emitWarning('', 1), expectedError);
+assert.throws(() => process.emitWarning('', '', 1), expectedError);
+assert.throws(() => process.emitWarning('', true), expectedError);
+assert.throws(() => process.emitWarning('', '', true), expectedError);
+assert.throws(() => process.emitWarning('', []), expectedError);
+assert.throws(() => process.emitWarning('', '', []), expectedError);
diff --git a/test/parallel/test-process-next-tick.js b/test/parallel/test-process-next-tick.js
index 1931320beb..9cbdfc6d3b 100644
--- a/test/parallel/test-process-next-tick.js
+++ b/test/parallel/test-process-next-tick.js
@@ -21,6 +21,7 @@
'use strict';
const common = require('../common');
+const assert = require('assert');
const N = 2;
function cb() {
@@ -36,3 +37,12 @@ process.on('uncaughtException', common.mustCall(N));
process.on('exit', function() {
process.removeAllListeners('uncaughtException');
});
+
+[null, 1, 'test', {}, [], Infinity, true].forEach((i) => {
+ assert.throws(() => process.nextTick(i),
+ common.expectsError({
+ code: 'ERR_INVALID_CALLBACK',
+ type: TypeError,
+ message: 'callback must be a function'
+ }));
+});
diff --git a/test/pseudo-tty/test-tty-stdout-end.js b/test/pseudo-tty/test-tty-stdout-end.js
index 86a42c4035..3c91977f90 100644
--- a/test/pseudo-tty/test-tty-stdout-end.js
+++ b/test/pseudo-tty/test-tty-stdout-end.js
@@ -1,14 +1,10 @@
'use strict';
-require('../common');
+const common = require('../common');
const assert = require('assert');
-const shouldThrow = function() {
- process.stdout.end();
-};
-
-const validateError = function(e) {
- return e instanceof Error &&
- e.message === 'process.stdout cannot be closed.';
-};
-
-assert.throws(shouldThrow, validateError);
+assert.throws(() => process.stdout.end(),
+ common.expectsError({
+ code: 'ERR_STDOUT_CLOSE',
+ type: Error,
+ message: 'process.stdout cannot be closed'
+ }));