denoland/deno · error · RangeError

outgoingHighWaterMark cannot be negative

Error message

outgoingHighWaterMark cannot be negative

What it means

WebTransportDatagramDuplexStream.outgoingHighWaterMark sizes the buffer/queue threshold for outgoing datagrams. Its setter in ext/web/webtransport.js takes an 'unrestricted double' and throws a RangeError when assigned a negative value or NaN. As with the incoming variant, values below 1 are clamped to 1 rather than erroring.

Source

Thrown at ext/web/webtransport.js:857

      throw new RangeError("incomingHighWaterMark cannot be negative");
    }
    if (value < 1) value = 1;
    this.#incomingHighWaterMark = value;
  }

  get outgoingHighWaterMark() {
    webidl.assertBranded(this, WebTransportDatagramDuplexStreamPrototype);
    return this.#outgoingHighWaterMark;
  }

  set outgoingHighWaterMark(value) {
    webidl.assertBranded(this, WebTransportDatagramDuplexStreamPrototype);
    value = webidl.converters["unrestricted double"](
      value,
      "Failed to execute 'outgoingHighWaterMark' on 'WebTransportDatagramDuplexStream'",
    );
    if (value < 0 || NumberIsNaN(value)) {
      throw new RangeError("outgoingHighWaterMark cannot be negative");
    }
    if (value < 1) value = 1;
    this.#outgoingHighWaterMark = value;
  }

  get maxDatagramSize() {
    webidl.assertBranded(this, WebTransportDatagramDuplexStreamPrototype);
    if (this.#conn) {
      return this.#conn.maxDatagramSize - this.#sessionIdBuf.length;
    }
    return 1024;
  }

  get readable() {
    webidl.assertBranded(this, WebTransportDatagramDuplexStreamPrototype);
    if (!this.#readable) {
      this.#readable = new ReadableStream({
        type: "bytes",

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Set a positive finite number appropriate for your datagram burst size.
  2. Replace negative sentinels with a real default before assignment.
  3. Validate with Number.isFinite(v) && v >= 0 first.
  4. Remember 0 is clamped to 1 — use a meaningful positive value instead.

Example fix

// before
duplex.outgoingHighWaterMark = size; // size can be -1 from config

// after
duplex.outgoingHighWaterMark =
  Number.isFinite(size) && size >= 1 ? size : 1;
Defensive patterns

Strategy: validation

Validate before calling

function toHighWaterMark(v, fallback = 1) {
  return Number.isFinite(v) && v >= 1 ? v : fallback;
}
duplex.outgoingHighWaterMark = toHighWaterMark(cfg.outHwm);

Type guard

function isValidHighWaterMark(v) {
  return typeof v === "number" && Number.isFinite(v) && v >= 0;
}

Try / catch

try { duplex.outgoingHighWaterMark = v; } catch (e) { if (e instanceof RangeError) duplex.outgoingHighWaterMark = 1; else throw e; }

Prevention

When it happens

Trigger: duplex.outgoingHighWaterMark = -1; NaN from math on undefined inputs; user-provided buffer sizes forwarded without validation.

Common situations: Performance-tuning knobs copied from other transports where 0 or -1 means 'default'; config reload paths assigning raw values; dividing by a variable that can be 0 producing Infinity-like or NaN edge cases.

Related errors


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