denoland/deno · error · RangeError
outgoingMaxAge cannot be negative
Error message
outgoingMaxAge cannot be negative
What it means
WebTransportDatagramDuplexStream.outgoingMaxAge sets a maximum age for outgoing datagrams on the sender side. Its setter in ext/web/webtransport.js takes an 'unrestricted double?' and throws a RangeError for negative values or NaN. Zero is converted to null, meaning no age limit is applied.
Source
Thrown at ext/web/webtransport.js:821
throw new RangeError("incomingMaxAge cannot be negative");
}
if (value === 0) value = null;
this.#incomingMaxAge = value;
}
get outgoingMaxAge() {
webidl.assertBranded(this, WebTransportDatagramDuplexStreamPrototype);
return this.#outgoingMaxAge;
}
set outgoingMaxAge(value) {
webidl.assertBranded(this, WebTransportDatagramDuplexStreamPrototype);
value = webidl.converters["unrestricted double?"](
value,
"Failed to execute 'outgoingMaxAge' on 'WebTransportDatagramDuplexStream'",
);
if (value < 0 || NumberIsNaN(value)) {
throw new RangeError("outgoingMaxAge cannot be negative");
}
if (value === 0) value = null;
this.#outgoingMaxAge = value;
}
get incomingHighWaterMark() {
webidl.assertBranded(this, WebTransportDatagramDuplexStreamPrototype);
return this.#incomingHighWaterMark;
}
set incomingHighWaterMark(value) {
webidl.assertBranded(this, WebTransportDatagramDuplexStreamPrototype);
value = webidl.converters["unrestricted double"](
value,
"Failed to execute 'incomingHighWaterMark' on 'WebTransportDatagramDuplexStream'",
);
if (value < 0 || NumberIsNaN(value)) {
throw new RangeError("incomingHighWaterMark cannot be negative");View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Assign a non-negative millisecond value or null.
- Clamp or reject user input before it reaches the setter.
- Treat 'unset' as null, and note 0 behaves the same as null.
- Check Number.isFinite before assigning any computed value.
Example fix
// before duplex.outgoingMaxAge = ageHint; // ageHint may be -1 or NaN // after duplex.outgoingMaxAge = Number.isFinite(ageHint) && ageHint > 0 ? ageHint : null;
Defensive patterns
Strategy: validation
Validate before calling
function toMaxAge(v) {
return Number.isFinite(v) && v > 0 ? v : null;
}
duplex.outgoingMaxAge = toMaxAge(ttlMs); Type guard
function isValidMaxAge(v) {
return v == null || (typeof v === "number" && Number.isFinite(v) && v >= 0);
} Try / catch
try { duplex.outgoingMaxAge = v; } catch (e) { if (e instanceof RangeError) duplex.outgoingMaxAge = null; else throw e; } Prevention
- Clamp user-supplied TTLs to positive numbers or null.
- Do not forward raw config numbers straight to setters.
- Treat 0 and null alike (both mean 'no age limit') in your config semantics.
When it happens
Trigger: duplex.outgoingMaxAge = -100; assigning NaN produced by arithmetic on undefined; forwarding a user-supplied TTL/config value without bounds-checking.
Common situations: Exposing maxAge configuration to users without validation; reusing '-1 means forever' conventions from other systems; computing age from timestamps where clock skew makes the result negative.
Related errors
- incomingMaxAge cannot be negative
- incomingHighWaterMark cannot be negative
- outgoingHighWaterMark cannot be negative
- BenchContext::start() has already been invoked
- ${prefix}Linter plugin name must only contain lowercase lett
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/8094d239452b701b.
Report an issue: GitHub.