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

url: port WHATWG URL API to internal/errors #12574

Closed
wants to merge 3 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
81 changes: 81 additions & 0 deletions doc/api/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,13 @@ found [here][online].
<a id="nodejs-error-codes"></a>
## Node.js Error Codes

<a id="ERR_ARG_NOT_ITERABLE"></a>
Copy link
Member

Choose a reason for hiding this comment

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

This can also be just ERR_INVALID_ARG_TYPE with Iterable as the expected type..no strong feelings about it though.

Copy link
Member

Choose a reason for hiding this comment

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

For this I think the more specific error is warranted.

### ERR_ARG_NOT_ITERABLE

The `'ERR_ARG_NOT_ITERABLE'` error code is 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_INVALID_ARG_TYPE"></a>
### ERR_INVALID_ARG_TYPE

Expand All @@ -574,6 +581,76 @@ an argument of the wrong type has been passed to a Node.js API.
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_INVALID_FILE_URL_HOST"></a>
### ERR_INVALID_FILE_URL_HOST

An error with the `'ERR_INVALID_FILE_URL_HOST'` code may be thrown when a
Node.js API that consumes `file:` URLs (such as certain functions in the
[`fs`][] module) encounters a file URL with an incompatible host. Currently,
this situation can only occur on Unix-like systems, where only `localhost` or
an empty host is supported.

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

An error with the `'ERR_INVALID_FILE_URL_PATH'` code may be thrown when a
Node.js API that consumes `file:` URLs (such as certain functions in the
[`fs`][] module) encounters a file URL with an incompatible path. The exact
semantics for determining whether a path can be used is platform-dependent.

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

The `'ERR_INVALID_THIS'` error code is used generically to identify that a
Node.js API function is called with an incompatible `this` value.

Example:

```js
const { URLSearchParams } = require('url');
const urlSearchParams = new URLSearchParams('foo=bar&baz=new');

const buf = Buffer.alloc(1);
urlSearchParams.has.call(buf, 'foo');
// Throws a TypeError with code 'ERR_INVALID_THIS'
```

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

An error with code `'ERR_INVALID_TUPLE'` is thrown when an element in the
`iterable` provided to the [WHATWG][WHATWG URL API] [`URLSearchParams`
constructor][`new URLSearchParams(iterable)`] does not represent a `[name,
value]` tuple – that is, if an element is not iterable, or does not consist of
exactly two elements.

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

An error using the `'ERR_INVALID_URL'` code is thrown when an invalid URL is
passed to the [WHATWG][WHATWG URL API] [`URL` constructor][`new URL(input)`] to
be parsed. The thrown error object typically has an additional property
`'input'` that contains the URL that failed to parse.
Copy link
Member

Choose a reason for hiding this comment

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

Note that at the moment input might not be exactly the same as the original input since it needs to go through trimming and String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8 first...we could've stored the original input, but that's for another PR to consider

Copy link
Member Author

Choose a reason for hiding this comment

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

Right, the REPLACE_INVALID_UTF8 is pretty edge-case, but trimming can indeed be something the user does not expect. Agreed on addressing this in a separate PR though.


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

The code `'ERR_INVALID_URL_SCHEME'` is used generically to signify an attempt
to use a URL of an incompatible scheme (aka protocol) for a specific purpose.
It is currently only used in the [WHATWG URL API][] support in the [`fs`][]
module (which only accepts URLs with `'file'` scheme), but may be used in other
Node.js APIs as well in the future.

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

The `'ERR_MISSING_ARGS'` error code is a generic error code for instances where
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.
Copy link
Member

Choose a reason for hiding this comment

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

In that case, why not just use 'ERR_INVALID_ARG_TYPE'?

Copy link
Member Author

Choose a reason for hiding this comment

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

'ERR_INVALID_ARG_TYPE' has the following templated message:

The "FOO" argument must be of type BAR.

In this case, it is not the question of what type the argument is, but whether it is defined at all.


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

Expand Down Expand Up @@ -626,11 +703,15 @@ likely an indication of a bug within Node.js itself.
[`process.on('uncaughtException')`]: process.html#process_event_uncaughtexception
[domains]: domain.html
[event emitter-based]: events.html#events_class_eventemitter
[`ERR_INVALID_ARG_TYPE`]: #ERR_INVALID_ARG_TYPE
[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
[try-catch]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch
[`new URL(input)`]: url.html#url_constructor_new_url_input_base
[`new URLSearchParams(iterable)`]: url.html#url_constructor_new_urlsearchparams_iterable
[V8's stack trace API]: https://github.com/v8/v8/wiki/Stack-Trace-API
[vm]: vm.html
[WHATWG URL API]: url.html#url_the_whatwg_url_api
56 changes: 46 additions & 10 deletions lib/internal/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,18 @@ module.exports = exports = {
// Any error code added here should also be added to the documentation
//
// 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_INVALID_ARG_TYPE', invalidArgType);
E('ERR_INVALID_CALLBACK', 'callback must be a function');
E('ERR_INVALID_FILE_URL_HOST', 'File URL host %s');
E('ERR_INVALID_FILE_URL_PATH', 'File URL path %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_MISSING_ARGS', missingArgs);
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');
Expand All @@ -91,22 +100,49 @@ E('ERR_UNKNOWN_BUILTIN_MODULE', (id) => `No such built-in module: ${id}`);

function invalidArgType(name, expected, actual) {
assert(name, 'name is required');
var msg = `The "${name}" argument must be ${oneOf(expected, 'type')}`;
if (arguments.length >= 3) {
msg += `. Received type ${actual !== null ? typeof actual : 'null'}`;
}
return msg;
}

function missingArgs(...args) {
assert(args.length > 0, 'At least one arg needs to be specified');
let msg = 'The ';
const len = args.length;
args = args.map((a) => `"${a}"`);
switch (len) {
case 1:
msg += `${args[0]} argument`;
break;
case 2:
msg += `${args[0]} and ${args[1]} arguments`;
break;
default:
msg += args.slice(0, len - 1).join(', ');
msg += `, and ${args[len - 1]} arguments`;
break;
}
return `${msg} must be specified`;
}

function oneOf(expected, thing) {
assert(expected, 'expected is required');
var msg = `The "${name}" argument must be `;
assert(typeof thing === 'string', 'thing is required');
if (Array.isArray(expected)) {
var len = expected.length;
const len = expected.length;
assert(len > 0, 'At least one expected value needs to be specified');
expected = expected.map((i) => String(i));
if (len > 1) {
msg += `one of type ${expected.slice(0, len - 1).join(', ')}, or ` +
if (len > 2) {
return `one of ${thing} ${expected.slice(0, len - 1).join(', ')}, or ` +
expected[len - 1];
} else if (len === 2) {
return `one of ${thing} ${expected[0]} or ${expected[1]}`;
} else {
msg += `of type ${expected[0]}`;
return `of ${thing} ${expected[0]}`;
}
} else {
msg += `of type ${String(expected)}`;
}
if (arguments.length >= 3) {
msg += `. Received type ${actual !== null ? typeof actual : 'null'}`;
return `of ${thing} ${String(expected)}`;
}
return msg;
}
Loading