Skip to content

Commit bff5d30

Browse files
BridgeARtargos
authored andcommitted
lib: move extra properties into error creation
This encapsulates the Node.js errors more by adding extra properties to an error inside of the function to create the error message instead of adding the properties at the call site. That simplifies the usage of our errors and makes sure the expected properties are always set. PR-URL: #26752 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 1458711 commit bff5d30

File tree

9 files changed

+78
-47
lines changed

9 files changed

+78
-47
lines changed

lib/_stream_readable.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -309,15 +309,13 @@ function addChunk(stream, state, chunk, addToFront) {
309309
}
310310

311311
function chunkInvalid(state, chunk) {
312-
var er;
313312
if (!Stream._isUint8Array(chunk) &&
314313
typeof chunk !== 'string' &&
315314
chunk !== undefined &&
316315
!state.objectMode) {
317-
er = new ERR_INVALID_ARG_TYPE(
316+
return new ERR_INVALID_ARG_TYPE(
318317
'chunk', ['string', 'Buffer', 'Uint8Array'], chunk);
319318
}
320-
return er;
321319
}
322320

323321

lib/internal/encoding.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -394,9 +394,7 @@ function makeTextDecoderICU() {
394394

395395
const ret = _decode(this[kHandle], input, flags);
396396
if (typeof ret === 'number') {
397-
const err = new ERR_ENCODING_INVALID_ENCODED_DATA(this.encoding);
398-
err.errno = ret;
399-
throw err;
397+
throw new ERR_ENCODING_INVALID_ENCODED_DATA(this.encoding, ret);
400398
}
401399
return ret.toString('ucs2');
402400
}

lib/internal/errors.js

+56-13
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ function lazyBuffer() {
4747
// and may have .path and .dest.
4848
class SystemError extends Error {
4949
constructor(key, context) {
50-
const prefix = getMessage(key, []);
50+
super();
51+
const prefix = getMessage(key, [], this);
5152
let message = `${prefix}: ${context.syscall} returned ` +
5253
`${context.code} (${context.message})`;
5354

@@ -56,7 +57,12 @@ class SystemError extends Error {
5657
if (context.dest !== undefined)
5758
message += ` => ${context.dest}`;
5859

59-
super(message);
60+
Object.defineProperty(this, 'message', {
61+
value: message,
62+
enumerable: false,
63+
writable: true,
64+
configurable: true
65+
});
6066
Object.defineProperty(this, kInfo, {
6167
configurable: false,
6268
enumerable: false,
@@ -150,7 +156,14 @@ let useOriginalName = false;
150156
function makeNodeErrorWithCode(Base, key) {
151157
return class NodeError extends Base {
152158
constructor(...args) {
153-
super(getMessage(key, args));
159+
super();
160+
const message = getMessage(key, args, this);
161+
Object.defineProperty(this, 'message', {
162+
value: message,
163+
enumerable: false,
164+
writable: true,
165+
configurable: true
166+
});
154167
}
155168

156169
get name() {
@@ -204,7 +217,7 @@ function E(sym, val, def, ...otherClasses) {
204217
codes[sym] = def;
205218
}
206219

207-
function getMessage(key, args) {
220+
function getMessage(key, args, self) {
208221
const msg = messages.get(key);
209222

210223
if (util === undefined) util = require('util');
@@ -216,7 +229,7 @@ function getMessage(key, args) {
216229
`Code: ${key}; The provided arguments length (${args.length}) does not ` +
217230
`match the required ones (${msg.length}).`
218231
);
219-
return msg.apply(null, args);
232+
return msg.apply(self, args);
220233
}
221234

222235
const expectedLength = (msg.match(/%[dfijoOs]/g) || []).length;
@@ -608,8 +621,10 @@ E('ERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE',
608621
'The `domain` module is in use, which is mutually exclusive with calling ' +
609622
'process.setUncaughtExceptionCaptureCallback()',
610623
Error);
611-
E('ERR_ENCODING_INVALID_ENCODED_DATA',
612-
'The encoded data was not valid for encoding %s', TypeError);
624+
E('ERR_ENCODING_INVALID_ENCODED_DATA', function(encoding, ret) {
625+
this.errno = ret;
626+
return `The encoded data was not valid for encoding ${encoding}`;
627+
}, TypeError);
613628
E('ERR_ENCODING_NOT_SUPPORTED', 'The "%s" encoding is not supported',
614629
RangeError);
615630
E('ERR_FALSY_VALUE_REJECTION', 'Promise was rejected with falsy value', Error);
@@ -652,7 +667,16 @@ E('ERR_HTTP2_INVALID_PSEUDOHEADER',
652667
'"%s" is an invalid pseudoheader or is used incorrectly', TypeError);
653668
E('ERR_HTTP2_INVALID_SESSION', 'The session has been destroyed', Error);
654669
E('ERR_HTTP2_INVALID_SETTING_VALUE',
655-
'Invalid value for setting "%s": %s', TypeError, RangeError);
670+
// Using default arguments here is important so the arguments are not counted
671+
// towards `Function#length`.
672+
function(name, actual, min = undefined, max = undefined) {
673+
this.actual = actual;
674+
if (min !== undefined) {
675+
this.min = min;
676+
this.max = max;
677+
}
678+
return `Invalid value for setting "${name}": ${actual}`;
679+
}, TypeError, RangeError);
656680
E('ERR_HTTP2_INVALID_STREAM', 'The stream has been destroyed', Error);
657681
E('ERR_HTTP2_MAX_PENDING_SETTINGS_ACK',
658682
'Maximum number of pending settings acknowledgements', Error);
@@ -685,7 +709,15 @@ E('ERR_HTTP2_SOCKET_UNBOUND',
685709
E('ERR_HTTP2_STATUS_101',
686710
'HTTP status code 101 (Switching Protocols) is forbidden in HTTP/2', Error);
687711
E('ERR_HTTP2_STATUS_INVALID', 'Invalid status code: %s', RangeError);
688-
E('ERR_HTTP2_STREAM_CANCEL', 'The pending stream has been canceled', Error);
712+
E('ERR_HTTP2_STREAM_CANCEL', function(error) {
713+
let msg = 'The pending stream has been canceled';
714+
if (error) {
715+
this.cause = error;
716+
if (typeof error.message === 'string')
717+
msg += ` (caused by: ${error.message})`;
718+
}
719+
return msg;
720+
}, Error);
689721
E('ERR_HTTP2_STREAM_ERROR', 'Stream closed with error code %s', Error);
690722
E('ERR_HTTP2_STREAM_SELF_DEPENDENCY',
691723
'A stream cannot depend on itself', Error);
@@ -709,7 +741,11 @@ E('ERR_INSPECTOR_CLOSED', 'Session was closed', Error);
709741
E('ERR_INSPECTOR_COMMAND', 'Inspector error %d: %s', Error);
710742
E('ERR_INSPECTOR_NOT_AVAILABLE', 'Inspector is not available', Error);
711743
E('ERR_INSPECTOR_NOT_CONNECTED', 'Session is not connected', Error);
712-
E('ERR_INVALID_ADDRESS_FAMILY', 'Invalid address family: %s', RangeError);
744+
E('ERR_INVALID_ADDRESS_FAMILY', function(addressType, host, port) {
745+
this.host = host;
746+
this.port = port;
747+
return `Invalid address family: ${addressType} ${host}:${port}`;
748+
}, RangeError);
713749
E('ERR_INVALID_ARG_TYPE',
714750
(name, expected, actual) => {
715751
assert(typeof name === 'string', "'name' must be a string");
@@ -812,7 +848,10 @@ E('ERR_INVALID_SYNC_FORK_INPUT',
812848
E('ERR_INVALID_THIS', 'Value of "this" must be of type %s', TypeError);
813849
E('ERR_INVALID_TUPLE', '%s must be an iterable %s tuple', TypeError);
814850
E('ERR_INVALID_URI', 'URI malformed', URIError);
815-
E('ERR_INVALID_URL', 'Invalid URL: %s', TypeError);
851+
E('ERR_INVALID_URL', function(input) {
852+
this.input = input;
853+
return `Invalid URL: ${input}`;
854+
}, TypeError);
816855
E('ERR_INVALID_URL_SCHEME',
817856
(expected) => `The URL must be ${oneOf(expected, 'scheme')}`, TypeError);
818857
E('ERR_IPC_CHANNEL_CLOSED', 'Channel closed', Error);
@@ -926,8 +965,12 @@ E('ERR_STREAM_WRAP', 'Stream has StringDecoder set or is in objectMode', Error);
926965
E('ERR_STREAM_WRITE_AFTER_END', 'write after end', Error);
927966
E('ERR_SYNTHETIC', 'JavaScript Callstack', Error);
928967
E('ERR_SYSTEM_ERROR', 'A system error occurred', SystemError);
929-
E('ERR_TLS_CERT_ALTNAME_INVALID',
930-
'Hostname/IP does not match certificate\'s altnames: %s', Error);
968+
E('ERR_TLS_CERT_ALTNAME_INVALID', function(reason, host, cert) {
969+
this.reason = reason;
970+
this.host = host;
971+
this.cert = cert;
972+
return `Hostname/IP does not match certificate's altnames: ${reason}`;
973+
}, Error);
931974
E('ERR_TLS_DH_PARAM_SIZE', 'DH parameter size %s is less than 2048', Error);
932975
E('ERR_TLS_HANDSHAKE_TIMEOUT', 'TLS handshake timeout', Error);
933976
E('ERR_TLS_INVALID_PROTOCOL_VERSION',

lib/internal/http2/core.js

+1-7
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,6 @@ function validateSettings(settings) {
812812
typeof settings.enablePush !== 'boolean') {
813813
const err = new ERR_HTTP2_INVALID_SETTING_VALUE('enablePush',
814814
settings.enablePush);
815-
err.actual = settings.enablePush;
816815
Error.captureStackTrace(err, 'validateSettings');
817816
throw err;
818817
}
@@ -1219,12 +1218,7 @@ class Http2Session extends EventEmitter {
12191218
this.removeAllListeners('timeout');
12201219

12211220
// Destroy any pending and open streams
1222-
const cancel = new ERR_HTTP2_STREAM_CANCEL();
1223-
if (error) {
1224-
cancel.cause = error;
1225-
if (typeof error.message === 'string')
1226-
cancel.message += ` (caused by: ${error.message})`;
1227-
}
1221+
const cancel = new ERR_HTTP2_STREAM_CANCEL(error);
12281222
state.pendingStreams.forEach((stream) => stream.destroy(cancel));
12291223
state.streams.forEach((stream) => stream.destroy(error));
12301224

lib/internal/http2/util.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -515,10 +515,8 @@ function assertIsObject(value, name, types) {
515515
function assertWithinRange(name, value, min = 0, max = Infinity) {
516516
if (value !== undefined &&
517517
(typeof value !== 'number' || value < min || value > max)) {
518-
const err = new ERR_HTTP2_INVALID_SETTING_VALUE.RangeError(name, value);
519-
err.min = min;
520-
err.max = max;
521-
err.actual = value;
518+
const err = new ERR_HTTP2_INVALID_SETTING_VALUE.RangeError(
519+
name, value, min, max);
522520
Error.captureStackTrace(err, assertWithinRange);
523521
throw err;
524522
}

lib/internal/url.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -238,9 +238,7 @@ function onParseComplete(flags, protocol, username, password,
238238
}
239239

240240
function onParseError(flags, input) {
241-
const error = new ERR_INVALID_URL(input);
242-
error.input = input;
243-
throw error;
241+
throw new ERR_INVALID_URL(input);
244242
}
245243

246244
function onParseProtocolComplete(flags, protocol, username, password,

lib/net.js

+9-8
Original file line numberDiff line numberDiff line change
@@ -989,19 +989,20 @@ function lookupAndConnect(self, options) {
989989
if (!self.connecting) return;
990990

991991
if (err) {
992-
// net.createConnection() creates a net.Socket object and
993-
// immediately calls net.Socket.connect() on it (that's us).
994-
// There are no event listeners registered yet so defer the
995-
// error event to the next tick.
992+
// net.createConnection() creates a net.Socket object and immediately
993+
// calls net.Socket.connect() on it (that's us). There are no event
994+
// listeners registered yet so defer the error event to the next tick.
995+
// TODO(BridgeAR): The error could either originate from user code or
996+
// by the C++ layer. The port is never the cause for the error as it is
997+
// not used in the lookup. We should probably just remove this.
996998
err.host = options.host;
997999
err.port = options.port;
9981000
err.message = err.message + ' ' + options.host + ':' + options.port;
9991001
process.nextTick(connectErrorNT, self, err);
10001002
} else if (addressType !== 4 && addressType !== 6) {
1001-
err = new ERR_INVALID_ADDRESS_FAMILY(addressType);
1002-
err.host = options.host;
1003-
err.port = options.port;
1004-
err.message = err.message + ' ' + options.host + ':' + options.port;
1003+
err = new ERR_INVALID_ADDRESS_FAMILY(addressType,
1004+
options.host,
1005+
options.port);
10051006
process.nextTick(connectErrorNT, self, err);
10061007
} else {
10071008
self._unrefTimer();

lib/tls.js

+1-5
Original file line numberDiff line numberDiff line change
@@ -242,11 +242,7 @@ exports.checkServerIdentity = function checkServerIdentity(hostname, cert) {
242242
}
243243

244244
if (!valid) {
245-
const err = new ERR_TLS_CERT_ALTNAME_INVALID(reason);
246-
err.reason = reason;
247-
err.host = hostname;
248-
err.cert = cert;
249-
return err;
245+
return new ERR_TLS_CERT_ALTNAME_INVALID(reason, hostname, cert);
250246
}
251247
};
252248

test/parallel/test-net-options-lookup.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,10 @@ function connectDoesNotThrow(input) {
3838
cb(null, '127.0.0.1', 100);
3939
});
4040

41-
s.on('error', common.expectsError({ code: 'ERR_INVALID_ADDRESS_FAMILY' }));
41+
s.on('error', common.expectsError({
42+
code: 'ERR_INVALID_ADDRESS_FAMILY',
43+
host: 'localhost',
44+
port: 0,
45+
message: 'Invalid address family: 100 localhost:0'
46+
}));
4247
}

0 commit comments

Comments
 (0)