Skip to content

Commit 4ec288a

Browse files
committed
quic: add QuicError js class
1 parent 0c9f9b3 commit 4ec288a

17 files changed

Lines changed: 944 additions & 11 deletions

doc/api/errors.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2651,6 +2651,19 @@ added:
26512651
26522652
Opening a QUIC stream failed.
26532653

2654+
<a id="ERR_QUIC_STREAM_ABORTED"></a>
2655+
2656+
### `ERR_QUIC_STREAM_ABORTED`
2657+
2658+
<!-- YAML
2659+
added: REPLACEME
2660+
-->
2661+
2662+
> Stability: 1 - Experimental
2663+
2664+
The Node.js error code for a [`QuicError`][] thrown to abort a QUIC stream
2665+
or session with an explicit application or transport error code.
2666+
26542667
<a id="ERR_QUIC_STREAM_RESET"></a>
26552668

26562669
### `ERR_QUIC_STREAM_RESET`
@@ -4449,6 +4462,7 @@ An error occurred trying to allocate memory. This should never happen.
44494462
[`MessagePort`]: worker_threads.md#class-messageport
44504463
[`Object.getPrototypeOf`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getPrototypeOf
44514464
[`Object.setPrototypeOf`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf
4465+
[`QuicError`]: quic.md#class-quicerror
44524466
[`REPL`]: repl.md
44534467
[`ServerResponse`]: http.md#class-httpserverresponse
44544468
[`Writable`]: stream.md#class-streamwritable

doc/api/quic.md

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,103 @@ added: v23.8.0
11141114

11151115
* Type: {bigint}
11161116

1117+
## Class: `QuicError`
1118+
1119+
<!-- YAML
1120+
added: REPLACEME
1121+
-->
1122+
1123+
> Stability: 1 - Experimental
1124+
1125+
A `QuicError` is an `Error` subclass that carries an explicit numeric
1126+
QUIC error code. Use it to abort a QUIC stream or session with a
1127+
specific application-protocol-defined error code rather than letting
1128+
the implementation pick a generic fallback.
1129+
1130+
The class is exported from `node:quic`:
1131+
1132+
```mjs
1133+
import { QuicError } from 'node:quic';
1134+
```
1135+
1136+
```cjs
1137+
const { QuicError } = require('node:quic');
1138+
```
1139+
1140+
When a `QuicError` is supplied to APIs that emit a wire frame
1141+
(currently [`writer.fail()`][]), the QUIC stack uses
1142+
[`error.errorCode`][] as the wire code for the resulting frame.
1143+
When any other value is supplied (for example a plain `Error`), the
1144+
implementation falls back to the negotiated application protocol's
1145+
"internal error" code (`H3_INTERNAL_ERROR` (`0x102`) for HTTP/3, or
1146+
the QUIC transport-layer `INTERNAL_ERROR` (`0x1`) for raw QUIC).
1147+
1148+
The Node.js error code (`error.code`) defaults to
1149+
`'ERR_QUIC_STREAM_ABORTED'`. Callers who need a more specific code
1150+
string can override it via `options.code` — the numeric QUIC code
1151+
is unaffected.
1152+
1153+
The Node.js error code is fixed at `'ERR_QUIC_STREAM_ABORTED'` so that
1154+
catch blocks can distinguish a `QuicError` from other Node.js errors
1155+
without checking the prototype chain. The numeric QUIC code lives on
1156+
the separate [`error.errorCode`][] property to avoid colliding with
1157+
the Node.js convention that `error.code` is a string.
1158+
1159+
### `new QuicError(message, options)`
1160+
1161+
<!-- YAML
1162+
added: REPLACEME
1163+
-->
1164+
1165+
* `message` {string} A human-readable description of the error.
1166+
* `options` {Object}
1167+
* `errorCode` {bigint | number} The numeric QUIC error code. Numbers
1168+
are coerced to `BigInt`. Must be a non-negative 62-bit unsigned
1169+
varint (`0n <= errorCode <= 2n ** 62n - 1n`).
1170+
* `code` {string} The Node.js-style error code string assigned to
1171+
`error.code`. Defaults to `'ERR_QUIC_STREAM_ABORTED'`.
1172+
* `type` {string} Either `'application'` (default) or `'transport'`.
1173+
Indicates whether the code is defined by the negotiated
1174+
application protocol (e.g. RFC 9114 for HTTP/3) or by the QUIC
1175+
transport layer (RFC 9000). Stream resets always carry application
1176+
codes, so the default is `'application'`.
1177+
1178+
```mjs
1179+
import { QuicError } from 'node:quic';
1180+
1181+
const err = new QuicError('rejecting stream', { errorCode: 0x10cn });
1182+
console.log(err.code); // 'ERR_QUIC_STREAM_ABORTED'
1183+
console.log(err.errorCode); // 268n
1184+
console.log(err.type); // 'application'
1185+
1186+
const custom = new QuicError('custom failure', {
1187+
errorCode: 0x10cn,
1188+
code: 'ERR_MY_QUIC_FAILURE',
1189+
});
1190+
console.log(custom.code); // 'ERR_MY_QUIC_FAILURE'
1191+
```
1192+
1193+
### `error.errorCode`
1194+
1195+
<!-- YAML
1196+
added: REPLACEME
1197+
-->
1198+
1199+
* Type: {bigint}
1200+
1201+
The numeric QUIC error code carried by this error.
1202+
1203+
### `error.type`
1204+
1205+
<!-- YAML
1206+
added: REPLACEME
1207+
-->
1208+
1209+
* Type: {string}
1210+
1211+
Either `'application'` or `'transport'`. Indicates the namespace of
1212+
[`error.errorCode`][].
1213+
11171214
## Class: `QuicStream`
11181215

11191216
<!-- YAML
@@ -1467,6 +1564,11 @@ The Writer has the following methods:
14671564
* `endSync()` — Synchronous close. Returns total bytes or `-1`.
14681565
* `end([options])` — Async close.
14691566
* `fail(reason)` — Errors the stream (sends RESET\_STREAM to peer).
1567+
When `reason` is a [`QuicError`][], its [`error.errorCode`][] is used
1568+
as the wire code on the resulting RESET\_STREAM frame; otherwise
1569+
the wire code falls back to the negotiated application protocol's
1570+
"internal error" code (`H3_INTERNAL_ERROR` (`0x102`) for HTTP/3, or
1571+
the QUIC transport-layer `INTERNAL_ERROR` (`0x1`) for raw QUIC).
14701572
* `desiredSize` — Available capacity in bytes, or `null` if closed/errored.
14711573

14721574
### `stream.setBody(body)`
@@ -3154,8 +3256,10 @@ throughput issues caused by flow control.
31543256
[NSS Key Log Format]: https://udn.realityripple.com/docs/Mozilla/Projects/NSS/Key_Log_Format
31553257
[`PerformanceEntry`]: perf_hooks.md#class-performanceentry
31563258
[`PerformanceObserver`]: perf_hooks.md#class-performanceobserver
3259+
[`QuicError`]: #class-quicerror
31573260
[`endpoint.maxConnectionsPerHost`]: #endpointmaxconnectionsperhost
31583261
[`endpoint.maxConnectionsTotal`]: #endpointmaxconnectionstotal
3262+
[`error.errorCode`]: #errorerrorcode
31593263
[`fs.promises.open(path, 'r')`]: fs.md#fspromisesopenpath-flags-mode
31603264
[`quic.connect()`]: #quicconnectaddress-options
31613265
[`quic.listen()`]: #quiclistencallback-options
@@ -3175,5 +3279,6 @@ throughput issues caused by flow control.
31753279
[`stream.setBody()`]: #streamsetbodybody
31763280
[`stream.setPriority()`]: #streamsetpriorityoptions
31773281
[`stream.writer`]: #streamwriter
3282+
[`writer.fail()`]: #streamwriter
31783283
[qlog]: https://datatracker.ietf.org/doc/draft-ietf-quic-qlog-main-schema/
31793284
[qvis]: https://qvis.quictools.info/

lib/internal/errors.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1691,6 +1691,7 @@ E('ERR_QUIC_APPLICATION_ERROR', 'A QUIC application error occurred. %d [%s]', Er
16911691
E('ERR_QUIC_CONNECTION_FAILED', 'QUIC connection failed', Error);
16921692
E('ERR_QUIC_ENDPOINT_CLOSED', 'QUIC endpoint closed: %s (%d)', Error);
16931693
E('ERR_QUIC_OPEN_STREAM_FAILED', 'Failed to open QUIC stream', Error);
1694+
E('ERR_QUIC_STREAM_ABORTED', '%s', Error);
16941695
E('ERR_QUIC_STREAM_RESET',
16951696
'The QUIC stream was reset by the peer with error code %d', Error);
16961697
E('ERR_QUIC_TRANSPORT_ERROR', 'A QUIC transport error occurred. %d [%s]', Error);

0 commit comments

Comments
 (0)