11cb0ef41Sopenharmony_ci# Using the internal/errors.js module
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ci## What is internal/errors.js
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ciThe `require('internal/errors')` module is an internal-only module that can be
61cb0ef41Sopenharmony_ciused to produce `Error`, `TypeError` and `RangeError` instances that use a
71cb0ef41Sopenharmony_cistatic, permanent error code and an optionally parameterized message.
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ciThe intent of the module is to allow errors provided by Node.js to be assigned a
101cb0ef41Sopenharmony_cipermanent identifier. Without a permanent identifier, userland code may need to
111cb0ef41Sopenharmony_ciinspect error messages to distinguish one error from another. An unfortunate
121cb0ef41Sopenharmony_ciresult of that practice is that changes to error messages result in broken code
131cb0ef41Sopenharmony_ciin the ecosystem. For that reason, Node.js has considered error message changes
141cb0ef41Sopenharmony_cito be breaking changes. By providing a permanent identifier for a specific
151cb0ef41Sopenharmony_cierror, we reduce the need for userland code to inspect error messages.
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_ciSwitching an existing error to use the `internal/errors` module must be
181cb0ef41Sopenharmony_ciconsidered a `semver-major` change.
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_ci## Using internal/errors.js
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ciThe `internal/errors` module exposes all custom errors as subclasses of the
231cb0ef41Sopenharmony_cibuiltin errors. After being added, an error can be found in the `codes` object.
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ciFor instance, an existing `Error` such as:
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_ci```js
281cb0ef41Sopenharmony_ciconst err = new TypeError(`Expected string received ${type}`);
291cb0ef41Sopenharmony_ci```
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ciCan be replaced by first adding a new error key into the `internal/errors.js`
321cb0ef41Sopenharmony_cifile:
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ci```js
351cb0ef41Sopenharmony_ciE('FOO', 'Expected string received %s', TypeError);
361cb0ef41Sopenharmony_ci```
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ciThen replacing the existing `new TypeError` in the code:
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_ci```js
411cb0ef41Sopenharmony_ciconst { FOO } = require('internal/errors').codes;
421cb0ef41Sopenharmony_ci// ...
431cb0ef41Sopenharmony_ciconst err = new FOO(type);
441cb0ef41Sopenharmony_ci```
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_ci## Adding new errors
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ciNew static error codes are added by modifying the `internal/errors.js` file
491cb0ef41Sopenharmony_ciand appending the new error codes to the end using the utility `E()` method.
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ci```js
521cb0ef41Sopenharmony_ciE('EXAMPLE_KEY1', 'This is the error value', TypeError);
531cb0ef41Sopenharmony_ciE('EXAMPLE_KEY2', (a, b) => `${a} ${b}`, RangeError);
541cb0ef41Sopenharmony_ci```
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ciThe first argument passed to `E()` is the static identifier. The second
571cb0ef41Sopenharmony_ciargument is either a String with optional `util.format()` style replacement
581cb0ef41Sopenharmony_citags (e.g. `%s`, `%d`), or a function returning a String. The optional
591cb0ef41Sopenharmony_ciadditional arguments passed to the `errors.message()` function (which is
601cb0ef41Sopenharmony_ciused by the `errors.Error`, `errors.TypeError` and `errors.RangeError` classes),
611cb0ef41Sopenharmony_ciwill be used to format the error message. The third argument is the base class
621cb0ef41Sopenharmony_cithat the new error will extend.
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ciIt is possible to create multiple derived
651cb0ef41Sopenharmony_ciclasses by providing additional arguments. The other ones will be exposed as
661cb0ef41Sopenharmony_ciproperties of the main class:
671cb0ef41Sopenharmony_ci
681cb0ef41Sopenharmony_ci<!-- eslint-disable no-unreachable -->
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ci```js
711cb0ef41Sopenharmony_ciE('EXAMPLE_KEY', 'Error message', TypeError, RangeError);
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci// In another module
741cb0ef41Sopenharmony_ciconst { EXAMPLE_KEY } = require('internal/errors').codes;
751cb0ef41Sopenharmony_ci// TypeError
761cb0ef41Sopenharmony_cithrow new EXAMPLE_KEY();
771cb0ef41Sopenharmony_ci// RangeError
781cb0ef41Sopenharmony_cithrow new EXAMPLE_KEY.RangeError();
791cb0ef41Sopenharmony_ci```
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci## Documenting new errors
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ciWhenever a new static error code is added and used, corresponding documentation
841cb0ef41Sopenharmony_cifor the error code should be added to the `doc/api/errors.md` file. This will
851cb0ef41Sopenharmony_cigive users a place to go to easily look up the meaning of individual error
861cb0ef41Sopenharmony_cicodes.
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ciIn case `make lint` fails to detect the new error codes added into `errors.md`,
891cb0ef41Sopenharmony_cithe markdown linting cache must be cleaned with `make lint-md-clean`.
901cb0ef41Sopenharmony_ci
911cb0ef41Sopenharmony_ci## Testing new errors
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ciWhen adding a new error, corresponding test(s) for the error message
941cb0ef41Sopenharmony_ciformatting may also be required. If the message for the error is a
951cb0ef41Sopenharmony_ciconstant string then no test is required for the error message formatting
961cb0ef41Sopenharmony_cias we can trust the error helper implementation. An example of this kind of
971cb0ef41Sopenharmony_cierror would be:
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ci```js
1001cb0ef41Sopenharmony_ciE('ERR_SOCKET_ALREADY_BOUND', 'Socket is already bound');
1011cb0ef41Sopenharmony_ci```
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ciIf the error message is not a constant string then tests to validate
1041cb0ef41Sopenharmony_cithe formatting of the message based on the parameters used when
1051cb0ef41Sopenharmony_cicreating the error should be added to
1061cb0ef41Sopenharmony_ci`test/parallel/test-internal-errors.js`.  These tests should validate
1071cb0ef41Sopenharmony_ciall of the different ways parameters can be used to generate the final
1081cb0ef41Sopenharmony_cimessage string. A simple example is:
1091cb0ef41Sopenharmony_ci
1101cb0ef41Sopenharmony_ci```js
1111cb0ef41Sopenharmony_ci// Test ERR_TLS_CERT_ALTNAME_INVALID
1121cb0ef41Sopenharmony_ciassert.strictEqual(
1131cb0ef41Sopenharmony_ci  errors.message('ERR_TLS_CERT_ALTNAME_INVALID', ['altname']),
1141cb0ef41Sopenharmony_ci  'Hostname/IP does not match certificate\'s altnames: altname');
1151cb0ef41Sopenharmony_ci```
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ciIn addition, there should also be tests which validate the use of the
1181cb0ef41Sopenharmony_cierror based on where it is used in the codebase.  If the error message is
1191cb0ef41Sopenharmony_cistatic, these tests should only validate that the expected code is received
1201cb0ef41Sopenharmony_ciand NOT validate the message.  This will reduce the amount of test change
1211cb0ef41Sopenharmony_cirequired when the message for an error changes.
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci```js
1241cb0ef41Sopenharmony_ciassert.throws(() => {
1251cb0ef41Sopenharmony_ci  socket.bind();
1261cb0ef41Sopenharmony_ci}, common.expectsError({
1271cb0ef41Sopenharmony_ci  code: 'ERR_SOCKET_ALREADY_BOUND',
1281cb0ef41Sopenharmony_ci  type: Error,
1291cb0ef41Sopenharmony_ci}));
1301cb0ef41Sopenharmony_ci```
1311cb0ef41Sopenharmony_ci
1321cb0ef41Sopenharmony_ciAvoid changing the format of the message after the error has been created.
1331cb0ef41Sopenharmony_ciIf it does make sense to do this for some reason, then additional tests
1341cb0ef41Sopenharmony_civalidating the formatting of the error message for those cases will
1351cb0ef41Sopenharmony_cilikely be required.
1361cb0ef41Sopenharmony_ci
1371cb0ef41Sopenharmony_ci## API
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_ci### Object: errors.codes
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ciExposes all internal error classes to be used by Node.js APIs.
1421cb0ef41Sopenharmony_ci
1431cb0ef41Sopenharmony_ci### Method: errors.message(key, args)
1441cb0ef41Sopenharmony_ci
1451cb0ef41Sopenharmony_ci* `key` {string} The static error identifier
1461cb0ef41Sopenharmony_ci* `args` {Array} Zero or more optional arguments passed as an Array
1471cb0ef41Sopenharmony_ci* Returns: {string}
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_ciReturns the formatted error message string for the given `key`.
150