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

  1. Assign a non-negative millisecond value or null.
  2. Clamp or reject user input before it reaches the setter.
  3. Treat 'unset' as null, and note 0 behaves the same as null.
  4. 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

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


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/8094d239452b701b. Report an issue: GitHub.