diff --git a/doc/api/errors.md b/doc/api/errors.md
index 1866ef333706a6..e0b8796c1e6803 100644
--- a/doc/api/errors.md
+++ b/doc/api/errors.md
@@ -956,12 +956,6 @@ added: v15.0.0
An invalid JSON Web Key was provided.
-
-
-### `ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE`
-
-The given crypto key object's type is invalid for the attempted operation.
-
### `ERR_CRYPTO_INVALID_KEYLEN`
@@ -992,6 +986,12 @@ added: v15.0.0
An invalid key type was provided.
+
+
+### `ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE`
+
+The given crypto key object's type is invalid for the attempted operation.
+
### `ERR_CRYPTO_INVALID_MESSAGELEN`
@@ -1140,6 +1140,23 @@ added:
The [debugger][] timed out waiting for the required host/port to be free.
+
+
+### `ERR_DIR_CLOSED`
+
+The [`fs.Dir`][] was previously closed.
+
+
+
+### `ERR_DIR_CONCURRENT_OPERATION`
+
+
+
+A synchronous read or close call was attempted on an [`fs.Dir`][] which has
+ongoing asynchronous operations.
+
### `ERR_DLOPEN_DISABLED`
@@ -1162,23 +1179,6 @@ added: v15.0.0
A call to `process.dlopen()` failed.
-
-
-### `ERR_DIR_CLOSED`
-
-The [`fs.Dir`][] was previously closed.
-
-
-
-### `ERR_DIR_CONCURRENT_OPERATION`
-
-
-
-A synchronous read or close call was attempted on an [`fs.Dir`][] which has
-ongoing asynchronous operations.
-
### `ERR_DNS_SET_SERVERS_FAILED`
@@ -1295,19 +1295,6 @@ added: v16.7.0
When using [`fs.cp()`][], `src` or `dest` pointed to an invalid path.
-
-
-### `ERR_HTTP_BODY_NOT_ALLOWED`
-
-An error is thrown when writing to an HTTP response which does not allow
-contents.
-
-
-
-### `ERR_HTTP_CONTENT_LENGTH_MISMATCH`
-
-Response body size doesn't match with the specified content-length header value.
-
### `ERR_FS_CP_FIFO_PIPE`
@@ -1373,49 +1360,6 @@ Path is a directory.
An attempt has been made to read a file whose size is larger than the maximum
allowed size for a `Buffer`.
-
-
-### `ERR_HTTP_HEADERS_SENT`
-
-An attempt was made to add more headers after the headers had already been sent.
-
-
-
-### `ERR_HTTP_INVALID_HEADER_VALUE`
-
-An invalid HTTP header value was specified.
-
-
-
-### `ERR_HTTP_INVALID_STATUS_CODE`
-
-Status code was outside the regular status code range (100-999).
-
-
-
-### `ERR_HTTP_REQUEST_TIMEOUT`
-
-The client has not sent the entire request within the allowed time.
-
-
-
-### `ERR_HTTP_SOCKET_ASSIGNED`
-
-The given [`ServerResponse`][] was already assigned a socket.
-
-
-
-### `ERR_HTTP_SOCKET_ENCODING`
-
-Changing the socket encoding is not allowed per [RFC 7230 Section 3][].
-
-
-
-### `ERR_HTTP_TRAILER_INVALID`
-
-The `Trailer` header was set even though the transfer encoding does not support
-that.
-
### `ERR_HTTP2_ALTSVC_INVALID_ORIGIN`
@@ -1462,13 +1406,6 @@ A non-specific HTTP/2 error has occurred.
New HTTP/2 Streams may not be opened after the `Http2Session` has received a
`GOAWAY` frame from the connected peer.
-
-
-### `ERR_HTTP2_HEADER_SINGLE_VALUE`
-
-Multiple values were provided for an HTTP/2 header field that was required to
-have only a single value.
-
### `ERR_HTTP2_HEADERS_AFTER_RESPOND`
@@ -1481,6 +1418,13 @@ An additional headers was specified after an HTTP/2 response was initiated.
An attempt was made to send multiple response headers.
+
+
+### `ERR_HTTP2_HEADER_SINGLE_VALUE`
+
+Multiple values were provided for an HTTP/2 header field that was required to
+have only a single value.
+
### `ERR_HTTP2_INFO_STATUS_NOT_ALLOWED`
@@ -1738,34 +1682,90 @@ is set for the `Http2Stream`.
`http2.connect()` was passed a URL that uses any protocol other than `http:` or
`https:`.
+
+
+### `ERR_HTTP_BODY_NOT_ALLOWED`
+
+An error is thrown when writing to an HTTP response which does not allow
+contents.
+
+
+
+### `ERR_HTTP_CONTENT_LENGTH_MISMATCH`
+
+Response body size doesn't match with the specified content-length header value.
+
+
+
+### `ERR_HTTP_HEADERS_SENT`
+
+An attempt was made to add more headers after the headers had already been sent.
+
+
+
+### `ERR_HTTP_INVALID_HEADER_VALUE`
+
+An invalid HTTP header value was specified.
+
+
+
+### `ERR_HTTP_INVALID_STATUS_CODE`
+
+Status code was outside the regular status code range (100-999).
+
+
+
+### `ERR_HTTP_REQUEST_TIMEOUT`
+
+The client has not sent the entire request within the allowed time.
+
+
+
+### `ERR_HTTP_SOCKET_ASSIGNED`
+
+The given [`ServerResponse`][] was already assigned a socket.
+
+
+
+### `ERR_HTTP_SOCKET_ENCODING`
+
+Changing the socket encoding is not allowed per [RFC 7230 Section 3][].
+
+
+
+### `ERR_HTTP_TRAILER_INVALID`
+
+The `Trailer` header was set even though the transfer encoding does not support
+that.
+
### `ERR_ILLEGAL_CONSTRUCTOR`
An attempt was made to construct an object using a non-public constructor.
-
+
-### `ERR_IMPORT_ATTRIBUTE_TYPE_INCOMPATIBLE`
+### `ERR_IMPORT_ATTRIBUTE_MISSING`
-An import `type` attribute was provided, but the specified module is of a
-different type.
+An import attribute is missing, preventing the specified module to be imported.
-
+
-### `ERR_IMPORT_ATTRIBUTE_MISSING`
+### `ERR_IMPORT_ATTRIBUTE_TYPE_INCOMPATIBLE`
-An import attribute is missing, preventing the specified module to be imported.
+An import `type` attribute was provided, but the specified module is of a
+different type.
@@ -2283,6 +2283,12 @@ function.
An error occurred while attempting to retrieve the JavaScript `undefined`
value.
+
+
+### `ERR_NON_CONTEXT_AWARE_DISABLED`
+
+A non-context-aware native addon was loaded in a process that disallows them.
+
### `ERR_NOT_BUILDING_SNAPSHOT`
@@ -2324,12 +2330,6 @@ OpenSSL crypto support.
An attempt was made to use features that require [ICU][], but Node.js was not
compiled with ICU support.
-
-
-### `ERR_NON_CONTEXT_AWARE_DISABLED`
-
-A non-context-aware native addon was loaded in a process that disallows them.
-
### `ERR_OPERATION_FAILED`
@@ -2459,6 +2459,19 @@ added: REPLACEME
Opening a QUIC stream failed.
+
+
+### `ERR_REQUIRE_ASYNC_MODULE`
+
+> Stability: 1 - Experimental
+
+When trying to `require()` a [ES Module][], the module turns out to be asynchronous.
+That is, it contains top-level await.
+
+To see where the top-level await is, use
+`--experimental-print-required-tla` (this would execute the modules
+before looking for the top-level awaits).
+
### `ERR_REQUIRE_CYCLE_MODULE`
@@ -2474,19 +2487,6 @@ To avoid the cycle, the `require()` call involved in a cycle should not happen
at the top-level of either an ES Module (via `createRequire()`) or a CommonJS
module, and should be done lazily in an inner function.
-
-
-### `ERR_REQUIRE_ASYNC_MODULE`
-
-> Stability: 1 - Experimental
-
-When trying to `require()` a [ES Module][], the module turns out to be asynchronous.
-That is, it contains top-level await.
-
-To see where the top-level await is, use
-`--experimental-print-required-tla` (this would execute the modules
-before looking for the top-level awaits).
-
### `ERR_REQUIRE_ESM`
@@ -3022,6 +3022,16 @@ import 'package-name'; // supported
`import` with URL schemes other than `file` and `data` is unsupported.
+
+
+### `ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING`
+
+
+
+Type stripping is not supported for files descendent of a `node_modules` directory.
+
### `ERR_UNSUPPORTED_RESOLVE_REQUEST`
@@ -3042,16 +3052,6 @@ try {
}
```
-
-
-### `ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING`
-
-
-
-Type stripping is not supported for files descendent of a `node_modules` directory.
-
### `ERR_USE_AFTER_CLOSE`
@@ -3067,18 +3067,18 @@ An attempt was made to use something that was already closed.
While using the Performance Timing API (`perf_hooks`), no valid performance
entry types are found.
-
-
-### `ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING_FLAG`
-
-A dynamic import callback was invoked without `--experimental-vm-modules`.
-
### `ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING`
A dynamic import callback was not specified.
+
+
+### `ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING_FLAG`
+
+A dynamic import callback was invoked without `--experimental-vm-modules`.
+
### `ERR_VM_MODULE_ALREADY_LINKED`
@@ -3164,25 +3164,6 @@ The `Worker` initialization failed.
The `execArgv` option passed to the `Worker` constructor contains
invalid flags.
-
-
-### `ERR_WORKER_NOT_RUNNING`
-
-An operation failed because the `Worker` instance is not currently running.
-
-
-
-### `ERR_WORKER_OUT_OF_MEMORY`
-
-The `Worker` instance terminated because it reached its memory limit.
-
-
-
-### `ERR_WORKER_PATH`
-
-The path for the main script of a worker is neither an absolute path
-nor a relative path starting with `./` or `../`.
-
### `ERR_WORKER_MESSAGING_ERRORED`
@@ -3231,6 +3212,25 @@ added: v22.5.0
Sending a message via [`postMessageToThread()`][] timed out.
+
+
+### `ERR_WORKER_NOT_RUNNING`
+
+An operation failed because the `Worker` instance is not currently running.
+
+
+
+### `ERR_WORKER_OUT_OF_MEMORY`
+
+The `Worker` instance terminated because it reached its memory limit.
+
+
+
+### `ERR_WORKER_PATH`
+
+The path for the main script of a worker is neither an absolute path
+nor a relative path starting with `./` or `../`.
+
### `ERR_WORKER_UNSERIALIZABLE_ERROR`
@@ -3249,6 +3249,21 @@ The requested functionality is not supported in worker threads.
Creation of a [`zlib`][] object failed due to incorrect configuration.
+
+
+### `HPE_CHUNK_EXTENSIONS_OVERFLOW`
+
+
+
+Too much data was received for a chunk extensions. In order to protect against
+malicious or malconfigured clients, if more than 16 KiB of data is received
+then an `Error` with this code will be emitted.
+
### `HPE_HEADER_OVERFLOW`
@@ -3268,21 +3283,6 @@ malconfigured clients, if more than `maxHeaderSize` of HTTP header data is recei
HTTP parsing will abort without a request or response object being created, and
an `Error` with this code will be emitted.
-
-
-### `HPE_CHUNK_EXTENSIONS_OVERFLOW`
-
-
-
-Too much data was received for a chunk extensions. In order to protect against
-malicious or malconfigured clients, if more than 16 KiB of data is received
-then an `Error` with this code will be emitted.
-
### `HPE_UNEXPECTED_CONTENT_LENGTH`
@@ -3326,6 +3326,16 @@ removed: v12.5.0
The value passed to `postMessage()` contained an object that is not supported
for transferring.
+
+
+### `ERR_CPU_USAGE`
+
+
+
+The native call from `process.cpuUsage` could not be processed.
+
### `ERR_CRYPTO_HASH_DIGEST_NO_UTF16`
@@ -3433,6 +3443,45 @@ removed: v10.0.0
Used when an invalid character is found in an HTTP response status message
(reason phrase).
+
+
+### `ERR_IMPORT_ASSERTION_TYPE_FAILED`
+
+
+
+An import assertion has failed, preventing the specified module to be imported.
+
+
+
+### `ERR_IMPORT_ASSERTION_TYPE_MISSING`
+
+
+
+An import assertion is missing, preventing the specified module to be imported.
+
+
+
+### `ERR_IMPORT_ASSERTION_TYPE_UNSUPPORTED`
+
+
+
+An import attribute is not supported by this version of Node.js.
+
### `ERR_INDEX_OUT_OF_RANGE`
@@ -3492,45 +3541,6 @@ changes:
An invalid transfer object was passed to `postMessage()`.
-
-
-### `ERR_IMPORT_ASSERTION_TYPE_FAILED`
-
-
-
-An import assertion has failed, preventing the specified module to be imported.
-
-
-
-### `ERR_IMPORT_ASSERTION_TYPE_MISSING`
-
-
-
-An import assertion is missing, preventing the specified module to be imported.
-
-
-
-### `ERR_IMPORT_ASSERTION_TYPE_UNSUPPORTED`
-
-
-
-An import attribute is not supported by this version of Node.js.
-
### `ERR_MANIFEST_ASSERT_INTEGRITY`
@@ -3860,12 +3870,6 @@ removed: v10.0.0
Used when a given value is out of the accepted range.
-
-
-### `ERR_VM_MODULE_NOT_LINKED`
-
-The module must be successfully linked before instantiation.
-
### `ERR_VM_MODULE_LINKING_ERRORED`
@@ -3879,6 +3883,12 @@ removed:
The linker function returned a module for which linking has failed.
+
+
+### `ERR_VM_MODULE_NOT_LINKED`
+
+The module must be successfully linked before instantiation.
+
### `ERR_WORKER_UNSUPPORTED_EXTENSION`
@@ -3903,16 +3913,6 @@ removed: v10.0.0
Used when an attempt is made to use a `zlib` object after it has already been
closed.
-
-
-### `ERR_CPU_USAGE`
-
-
-
-The native call from `process.cpuUsage` could not be processed.
-
## OpenSSL Error Codes
diff --git a/tools/eslint-rules/documented-errors.js b/tools/eslint-rules/documented-errors.js
index 39021d973f2413..bb13880016328a 100644
--- a/tools/eslint-rules/documented-errors.js
+++ b/tools/eslint-rules/documented-errors.js
@@ -1,5 +1,6 @@
'use strict';
+const assert = require('assert');
const fs = require('fs');
const path = require('path');
const { isDefiningError } = require('./rules-utils.js');
@@ -12,48 +13,55 @@ const doc = fs.readFileSync(docPath, 'utf8');
function getErrorsInDoc() {
const lines = doc.split('\n');
let currentHeader;
- const errors = new Map();
+ const errors = new Set();
+ const legacyErrors = new Set();
const codePattern = /^### `([^`]+)`$/;
const anchorPattern = /^<\/a>$/;
- function parse(line, legacy) {
- const error = { legacy };
- let code;
+ let previousAnchor;
- const codeMatch = line.match(codePattern);
- if (codeMatch) {
- error.header = true;
- code = codeMatch[1];
- }
-
- const anchorMatch = line.match(anchorPattern);
+ function parse(line, legacy, lineNumber) {
+ const anchorMatch = anchorPattern.exec(line);
if (anchorMatch) {
- error.anchor = true;
- code ??= anchorMatch[1];
+ const code = anchorMatch[1];
+ if (previousAnchor != null && previousAnchor > code) {
+ throw new Error(`Unordered error anchor in ${docPath}:${lineNumber}`, { cause: `${previousAnchor} ≤ ${code}` });
+ }
+ previousAnchor = code;
+ return;
}
- if (!code) return;
+ const codeMatch = codePattern.exec(line);
+ if (codeMatch == null) return;
- // If the code already exists in the Map, merge the new error data
- errors.set(code, {
- ...errors.get(code),
- ...error,
- });
+ const code = codeMatch[1];
+ if (previousAnchor == null) {
+ throw new Error(`Missing error anchor in ${docPath}:${lineNumber}`, { cause: code });
+ }
+ assert.strictEqual(code, previousAnchor, `Error anchor do not match with error code in ${docPath}:${lineNumber}`);
+
+ if (legacy && errors.has(code)) {
+ throw new Error(`Error is documented both as legacy and non-legacy in ${docPath}:${lineNumber}`, { cause: code });
+ }
+ (legacy ? legacyErrors : errors).add(code);
}
+ let lineNumber = 0;
for (const line of lines) {
+ lineNumber++;
if (line.startsWith('## ')) currentHeader = line.substring(3);
- if (currentHeader === 'Node.js error codes') parse(line, false);
- if (currentHeader === 'Legacy Node.js error codes') parse(line, true);
+ if (currentHeader === 'Node.js error codes') parse(line, false, lineNumber);
+ if (line === '## Legacy Node.js error codes') previousAnchor = null;
+ if (currentHeader === 'Legacy Node.js error codes') parse(line, true, lineNumber);
}
- return errors;
+ return { errors, legacyErrors };
}
// Main rule export
module.exports = {
create(context) {
- const errors = getErrorsInDoc();
+ const { errors, legacyErrors } = getErrorsInDoc();
return {
ExpressionStatement(node) {
if (!isDefiningError(node)) return;
@@ -61,27 +69,15 @@ module.exports = {
const code = node.expression.arguments?.[0]?.value;
if (!code) return;
- const err = errors.get(code); // Use Map's get method to retrieve the error
-
- if (!err || !err.header) {
+ if (legacyErrors.has(code)) {
context.report({
node,
- message: `"${code}" is not documented in doc/api/errors.md`,
- });
- if (!err) return;
- }
-
- if (!err.anchor) {
- context.report({
- node,
- message: `doc/api/errors.md does not have an anchor for "${code}"`,
+ message: `"${code}" is marked as legacy, yet it is used in lib/.`,
});
- }
-
- if (err.legacy) {
+ } else if (!errors.has(code)) {
context.report({
node,
- message: `"${code}" is marked as legacy, yet it is used in lib/.`,
+ message: `"${code}" is not documented in doc/api/errors.md`,
});
}
},