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: improve error types #13857

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 94 additions & 12 deletions doc/api/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -568,41 +568,85 @@ found [here][online].
Used generically to identify that an iterable argument (i.e. a value that works
with `for...of` loops) is required, but not provided to a Node.js API.

<a id="ERR_ASSERTION"></a>
### ERR_ASSERTION

Used as special type of error that can be triggered whenever Node.js detects an
exceptional logic violation that should never occur. These are raised typically
by the `assert` module.

<a id="ERR_CONSOLE_WRITABLE_STREAM"></a>
### ERR_CONSOLE_WRITABLE_STREAM

Used when `Console` is instantiated without `stdout` stream or when `stdout` or
`stderr` streams are not writable.

<a id="ERR_CPU_USAGE"></a>
### ERR_CPU_USAGE

Used when the native call from `process.cpuUsage` cannot be processed properly.

<a id="ERR_FALSY_VALUE_REJECTION"></a>
### ERR_FALSY_VALUE_REJECTION

The `ERR_FALSY_VALUE_REJECTION` error code is used by the `util.callbackify()`
API when a callbackified `Promise` is rejected with a falsy value (e.g. `null`).

<a id="ERR_HTTP_HEADERS_SENT"></a>
### ERR_HTTP_HEADERS_SENT

Used when headers have already been sent and another attempt is made to add
more headers.

<a id="ERR_HTTP_INVALID_STATUS_CODE"></a>
### ERR_HTTP_INVALID_STATUS_CODE

Used for status codes outside the regular status code ranges (100-999).

<a id="ERR_HTTP_TRAILER_INVALID"></a>
### ERR_HTTP_TRAILER_INVALID

Used when the `Trailer` header is set even though the transfer encoding does not
support that.

<a id="ERR_INDEX_OUT_OF_RANGE"></a>
### ERR_INDEX_OUT_OF_RANGE

Used when a given index is out of the accepted range.
Used when a given index is out of the accepted range (e.g. negative offsets).

<a id="ERR_INVALID_ARG_TYPE"></a>
### ERR_INVALID_ARG_TYPE

Used generically to identify that an argument of the wrong type has been passed
to a Node.js API.

<a id="ERR_INVALID_ARRAY_LENGTH"></a>
### ERR_INVALID_ARRAY_LENGTH

Used when an Array is not of the expected length or in a valid range.

<a id="ERR_INVALID_CALLBACK"></a>
### ERR_INVALID_CALLBACK

Used generically to identify that a callback function is required and has not
been provided to a Node.js API.

<a id="ERR_INVALID_CHAR"></a>
### ERR_INVALID_CHAR

Used when invalid characters are detected in headers.

<a id="ERR_INVALID_CURSOR_POS"></a>
### ERR_INVALID_CURSOR_POS

The `'ERR_INVALID_CURSOR_POS'` is thrown specifically when a cursor on a given
stream is attempted to move to a specified row without a specified column.

<a id="ERR_INVALID_FD"></a>
### ERR_INVALID_FD

Used when a file descriptor ('fd') is not valid (e.g. it has a negative value).

<a id="ERR_INVALID_FILE_URL_HOST"></a>
### ERR_INVALID_FILE_URL_HOST

Expand Down Expand Up @@ -638,6 +682,12 @@ passed in an options object.
Used when both `breakEvalOnSigint` and `eval` options are set
in the REPL config, which is not supported.

<a id="ERR_INVALID_REPL_HISTORY"></a>
### ERR_INVALID_REPL_HISTORY

Used in the `repl` in case the old history file is used and an error occurred
while trying to read and parse it.

<a id="ERR_INVALID_SYNC_FORK_INPUT"></a>
### ERR_INVALID_SYNC_FORK_INPUT

Expand Down Expand Up @@ -716,14 +766,33 @@ synchronous forked Node.js process. See the documentation for the
<a id="ERR_MISSING_ARGS"></a>
### ERR_MISSING_ARGS

Used when a required argument of a Node.js API is not passed. This is currently
only used in the [WHATWG URL API][] for strict compliance with the specification
(which in some cases may accept `func(undefined)` but not `func()`). In most
native Node.js APIs, `func(undefined)` and `func()` are treated identically, and
the [`ERR_INVALID_ARG_TYPE`][] error code may be used instead.
Used when a required argument of a Node.js API is not passed. This is only used
for strict compliance with the API specification (which in some cases may accept
`func(undefined)` but not `func()`). In most native Node.js APIs,
`func(undefined)` and `func()` are treated identically, and the
[`ERR_INVALID_ARG_TYPE`][] error code may be used instead.

<a id="ERR_MULTIPLE_CALLBACK"></a>
### ERR_MULTIPLE_CALLBACK

Used when a callback is called more then once.

*Note*: A callback is almost always meant to only be called once as the query
can either be fulfilled or rejected but not both at the same time. The latter
would be possible by calling a callback more then once.

<a id="ERR_NO_CRYPTO"></a>
### ERR_NO_CRYPTO

Used when an attempt is made to use crypto features while Node.js is not
compiled with OpenSSL crypto support.

<a id="ERR_PARSE_HISTORY_DATA"></a>
### ERR_PARSE_HISTORY_DATA

<a id="ERR_SOCKET_ALREADY_BOUND"></a>
### ERR_SOCKET_ALREADY_BOUND

Used when an attempt is made to bind a socket that has already been bound.

<a id="ERR_SOCKET_BAD_PORT"></a>
Expand All @@ -748,12 +817,6 @@ Used when data cannot be sent on a socket.

Used when a call is made and the UDP subsystem is not running.

<a id="ERR_NO_CRYPTO"></a>
### ERR_NO_CRYPTO

Used when an attempt is made to use crypto features while Node.js is not
compiled with OpenSSL crypto support.

<a id="ERR_STDERR_CLOSE"></a>
### ERR_STDERR_CLOSE

Expand All @@ -766,6 +829,19 @@ Node.js does not allow `stdout` or `stderr` Streams to be closed by user code.
Used 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_STREAM_HAS_STRINGDECODER"></a>
### ERR_STREAM_HAS_STRINGDECODER

Used to prevent an abort if a string decoder was set on the Socket.

Example
```js
const Socket = require('net').Socket;
const instance = new Socket();

instance.setEncoding('utf-8');
```

<a id="ERR_UNKNOWN_BUILTIN_MODULE"></a>
### ERR_UNKNOWN_BUILTIN_MODULE

Expand Down Expand Up @@ -795,6 +871,11 @@ Used when an attempt is made to launch a Node.js process with an unknown
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_V8BREAKITERATOR"></a>
### ERR_V8BREAKITERATOR

Used when the V8 BreakIterator API is used but the full ICU data set is not
installed.

[`ERR_INVALID_ARG_TYPE`]: #ERR_INVALID_ARG_TYPE
[`child.kill()`]: child_process.html#child_process_child_kill_signal
Expand All @@ -817,6 +898,7 @@ are most likely an indication of a bug within Node.js itself.
[domains]: domain.html
[event emitter-based]: events.html#events_class_eventemitter
[file descriptors]: https://en.wikipedia.org/wiki/File_descriptor
[intl wiki]: https://github.com/nodejs/node/wiki/Intl
[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
Expand Down
12 changes: 4 additions & 8 deletions lib/_http_server.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,10 +213,8 @@ function writeHead(statusCode, reason, obj) {
if (k) this.setHeader(k, obj[k]);
}
}
if (k === undefined) {
if (this._header) {
throw new errors.Error('ERR_HTTP_HEADERS_SENT');
}
if (k === undefined && this._header) {
throw new errors.Error('ERR_HTTP_HEADERS_SENT');
}
// only progressive api is used
headers = this[outHeadersKey];
Expand All @@ -225,10 +223,8 @@ function writeHead(statusCode, reason, obj) {
headers = obj;
}

if (common._checkInvalidHeaderChar(this.statusMessage)) {
throw new errors.Error('ERR_HTTP_INVALID_CHAR',
'Invalid character in statusMessage.');
}
if (common._checkInvalidHeaderChar(this.statusMessage))
throw new errors.Error('ERR_INVALID_CHAR', 'statusMessage');

var statusLine = 'HTTP/1.1 ' + statusCode + ' ' + this.statusMessage + CRLF;

Expand Down
4 changes: 2 additions & 2 deletions lib/_stream_transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,7 @@ function afterTransform(er, data) {
var cb = ts.writecb;

if (!cb) {
return this.emit('error',
new errors.Error('ERR_TRANSFORM_MULTIPLE_CALLBACK'));
return this.emit('error', new errors.Error('ERR_MULTIPLE_CALLBACK'));
}

ts.writechunk = null;
Expand Down Expand Up @@ -207,6 +206,7 @@ function done(stream, er, data) {
if (data != null) // single equals check for both `null` and `undefined`
stream.push(data);

// TODO(BridgeAR): Write a test for these two error cases
// if there's nothing in the write buffer, then that means
// that nothing more will ever be provided
if (stream._writableState.length)
Expand Down
2 changes: 1 addition & 1 deletion lib/dgram.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ function newHandle(type) {
return handle;
}

throw new errors.Error('ERR_SOCKET_BAD_TYPE');
throw new errors.TypeError('ERR_SOCKET_BAD_TYPE');
}


Expand Down
74 changes: 35 additions & 39 deletions lib/internal/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,32 +110,32 @@ module.exports = exports = {
//
// Note: Please try to keep these in alphabetical order
E('ERR_ARG_NOT_ITERABLE', '%s must be iterable');
E('ERR_ASSERTION', (msg) => msg);
E('ERR_ASSERTION', '%s');
E('ERR_CONSOLE_WRITABLE_STREAM',
(name) => `Console expects a writable stream instance for ${name}`);
E('ERR_CPU_USAGE', (errMsg) => `Unable to obtain cpu usage ${errMsg}`);
'Console expects a writable stream instance for %s');
E('ERR_CPU_USAGE', 'Unable to obtain cpu usage %s');
E('ERR_FALSY_VALUE_REJECTION', 'Promise was rejected with falsy value');
E('ERR_HTTP_HEADERS_SENT',
'Cannot render headers after they are sent to the client');
E('ERR_HTTP_INVALID_CHAR', 'Invalid character in statusMessage.');
E('ERR_HTTP_INVALID_STATUS_CODE',
(originalStatusCode) => `Invalid status code: ${originalStatusCode}`);
E('ERR_HTTP_INVALID_STATUS_CODE', 'Invalid status code: %s');
E('ERR_HTTP_TRAILER_INVALID',
'Trailers are invalid with this transfer encoding');
E('ERR_INDEX_OUT_OF_RANGE', 'Index out of range');
E('ERR_INVALID_ARG_TYPE', invalidArgType);
E('ERR_INVALID_ARRAY_LENGTH',
(name, length, actual) => {
let msg = `The "${name}" array must have a length of ${length}`;
if (arguments.length > 2) {
const len = Array.isArray(actual) ? actual.length : actual;
msg += `. Received length ${len}`;
}
return msg;
const assert = lazyAssert();
assert.strictEqual(typeof actual, 'number');
return `The "${name}" array must have a length of ${
length}. Received length ${actual}`;
});
E('ERR_INVALID_ARG_TYPE', invalidArgType);
E('ERR_INVALID_CALLBACK', 'callback must be a function');
E('ERR_INVALID_FD', (fd) => `"fd" must be a positive integer: ${fd}`);
E('ERR_INVALID_CALLBACK', 'Callback must be a function');
E('ERR_INVALID_CHAR', 'Invalid character in %s');
E('ERR_INVALID_CURSOR_POS',
'Cannot set cursor row without setting its column');
E('ERR_INVALID_FILE_URL_HOST', 'File URL host %s');
E('ERR_INVALID_FD', '"fd" must be a positive integer: %s');
E('ERR_INVALID_FILE_URL_HOST',
'File URL host must be "localhost" or empty on %s');
E('ERR_INVALID_FILE_URL_PATH', 'File URL path %s');
E('ERR_INVALID_HANDLE_TYPE', 'This handle type cannot be sent');
E('ERR_INVALID_OPT_VALUE',
Expand All @@ -144,47 +144,42 @@ E('ERR_INVALID_OPT_VALUE',
});
E('ERR_INVALID_REPL_EVAL_CONFIG',
'Cannot specify both "breakEvalOnSigint" and "eval" for REPL');
E('ERR_INVALID_REPL_HISTORY', 'Expected array, got %s');
E('ERR_INVALID_SYNC_FORK_INPUT',
(value) => {
return 'Asynchronous forks do not support Buffer, Uint8Array or string' +
`input: ${value}`;
});
'Asynchronous forks do not support Buffer, Uint8Array or string input: %s');
E('ERR_INVALID_THIS', 'Value of "this" must be of type %s');
E('ERR_INVALID_TUPLE', '%s must be an iterable %s tuple');
E('ERR_INVALID_URL', 'Invalid URL: %s');
E('ERR_INVALID_URL_SCHEME',
(expected) => `The URL must be ${oneOf(expected, 'scheme')}`);
E('ERR_INVALID_REPL_HISTORY',
(repl_history) => `Expected array, got ${repl_history}`);
E('ERR_IPC_CHANNEL_CLOSED', 'channel closed');
(expected) => {
lazyAssert();
return `The URL must be ${oneOf(expected, 'scheme')}`;
});
E('ERR_IPC_CHANNEL_CLOSED', 'Channel closed');
E('ERR_IPC_DISCONNECTED', 'IPC channel is already disconnected');
E('ERR_IPC_ONE_PIPE', 'Child process can have only one IPC pipe');
E('ERR_IPC_SYNC_FORK', 'IPC cannot be used with synchronous forks');
E('ERR_MISSING_ARGS', missingArgs);
E('ERR_PARSE_HISTORY_DATA',
(oldHistoryPath) => `Could not parse history data in ${oldHistoryPath}`);
E('ERR_MULTIPLE_CALLBACK', 'Callback called multiple times');
E('ERR_NO_CRYPTO', 'Node.js is not compiled with OpenSSL crypto support');
E('ERR_PARSE_HISTORY_DATA', 'Could not parse history data in %s');
E('ERR_SOCKET_ALREADY_BOUND', 'Socket is already bound');
E('ERR_SOCKET_BAD_TYPE',
'Bad socket type specified. Valid types are: udp4, udp6');
E('ERR_SOCKET_CANNOT_SEND', 'Unable to send data');
E('ERR_SOCKET_BAD_PORT', 'Port should be > 0 and < 65536');
E('ERR_SOCKET_DGRAM_NOT_RUNNING', 'Not running');
E('ERR_STDERR_CLOSE', 'process.stderr cannot be closed');
E('ERR_STDOUT_CLOSE', 'process.stdout cannot be closed');
E('ERR_STREAM_HAS_STRINGDECODER', 'Stream has StringDecoder');
E('ERR_TRANSFORM_ALREADY_TRANSFORMING',
'Calling transform done when still transforming');
E('ERR_TRANSFORM_MULTIPLE_CALLBACK', 'Callback called multiple times');
E('ERR_TRANSFORM_WITH_LENGTH_0',
'Calling transform done when ws.length != 0');
E('ERR_HTTP_TRAILER_INVALID',
'Trailers are invalid with this transfer encoding');
E('ERR_UNKNOWN_BUILTIN_MODULE', (id) => `No such built-in module: ${id}`);
E('ERR_UNKNOWN_SIGNAL', (signal) => `Unknown signal: ${signal}`);
'Calling transform done when writableState.length != 0');
E('ERR_UNKNOWN_SIGNAL', 'Unknown signal: %s');
E('ERR_UNKNOWN_STDIN_TYPE', 'Unknown stdin file type');
E('ERR_UNKNOWN_STREAM_TYPE', 'Unknown stream file type');
E('ERR_SOCKET_ALREADY_BOUND', 'Socket is already bound');
E('ERR_SOCKET_BAD_TYPE',
'Bad socket type specified. Valid types are: udp4, udp6');
E('ERR_SOCKET_CANNOT_SEND', 'Unable to send data');
E('ERR_SOCKET_BAD_PORT', 'Port should be > 0 and < 65536');
E('ERR_SOCKET_DGRAM_NOT_RUNNING', 'Not running');
E('ERR_V8BREAKITERATOR', 'full ICU data not installed. ' +
E('ERR_V8BREAKITERATOR', 'Full ICU data not installed. ' +
'See https://github.com/nodejs/node/wiki/Intl');
// Add new errors from here...

Expand All @@ -200,6 +195,7 @@ function invalidArgType(name, expected, actual) {
}

function missingArgs(...args) {
const assert = lazyAssert();
assert(args.length > 0, 'At least one arg needs to be specified');
let msg = 'The ';
const len = args.length;
Expand Down
4 changes: 2 additions & 2 deletions lib/internal/process.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ function setup_hrtime() {
}
if (time.length !== 2) {
throw new errors.TypeError('ERR_INVALID_ARRAY_LENGTH', 'time', 2,
time);
time.length);
}

const sec = (hrValues[0] * 0x100000000 + hrValues[1]) - time[0];
Expand Down Expand Up @@ -181,7 +181,7 @@ function setupKillAndExit() {
if (lazyConstants()[sig]) {
err = process._kill(pid, lazyConstants()[sig]);
} else {
throw new errors.Error('ERR_UNKNOWN_SIGNAL', `${sig}`);
throw new errors.TypeError('ERR_UNKNOWN_SIGNAL', sig);
}
}

Expand Down
3 changes: 1 addition & 2 deletions lib/internal/url.js
Original file line number Diff line number Diff line change
Expand Up @@ -1352,8 +1352,7 @@ function getPathFromURLWin32(url) {

function getPathFromURLPosix(url) {
if (url.hostname !== '') {
return new errors.TypeError('ERR_INVALID_FILE_URL_HOST',
`must be "localhost" or empty on ${platform}`);
return new errors.TypeError('ERR_INVALID_FILE_URL_HOST', platform);
}
var pathname = url.pathname;
for (var n = 0; n < pathname.length; n++) {
Expand Down
Loading