websockets/ws · error · TypeError

Invalid value for parameter

Error message

Invalid value for parameter "${key}": ${value}

What it means

Thrown (as TypeError) by `PerMessageDeflate.normalizeParams()` when validating `client_max_window_bits`: the value is not the bare flag `true`, and coercing it with `+value` does not yield an integer in the allowed range [8, 15] defined by RFC 7692. The offending `value` is interpolated into the message.

Solutions

  1. Ensure `client_max_window_bits` is either the bare flag (`true`, advertised without a value) or an integer between 8 and 15 inclusive.
  2. Generate offers with the library's `offer()` method rather than hand-coding them.
  3. Catch the TypeError during the handshake and close with code 1002.

Example fix

// before
pmd.normalizeParams([{ client_max_window_bits: ['7'] }]);

// after
pmd.normalizeParams([{ client_max_window_bits: ['12'] }]);
Defensive patterns

Strategy: validation

Validate before calling

// Validate client_max_window_bits before negotiation.
function validClientMaxWindowBits(v) {
  return v === true || (Number.isInteger(+v) && +v >= 8 && +v <= 15);
}

Try / catch

try {
  perMessageDeflate.accept(parsedOffers);
} catch (err) {
  if (err instanceof TypeError && /client_max_window_bits/.test(err.message)) {
    abortHandshake(socket, 1002);
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: A peer offers `client_max_window_bits=7`, `client_max_window_bits=16`, `client_max_window_bits=abc`, or any non-numeric, non-`true` value; `normalizeParams` (called from `accept()`) throws.

Common situations: A buggy peer advertises an out-of-range window size; a fuzzer; a misconfigured client passing a string instead of a number.

Related errors


AI-assisted analysis of websockets/ws@c791e707ea (2026-08-06). Data as JSON: /api/errors/693f243481802dce. Report an issue: GitHub.

Appendix: source

Thrown at lib/permessage-deflate.js:261

   * @return {Array} The offers/response with normalized parameters
   * @private
   */
  normalizeParams(configurations) {
    configurations.forEach((params) => {
      Object.keys(params).forEach((key) => {
        let value = params[key];

        if (value.length > 1) {
          throw new Error(`Parameter "${key}" must have only a single value`);
        }

        value = value[0];

        if (key === 'client_max_window_bits') {
          if (value !== true) {
            const num = +value;
            if (!Number.isInteger(num) || num < 8 || num > 15) {
              throw new TypeError(
                `Invalid value for parameter "${key}": ${value}`
              );
            }
            value = num;
          } else if (!this._isServer) {
            throw new TypeError(
              `Invalid value for parameter "${key}": ${value}`
            );
          }
        } else if (key === 'server_max_window_bits') {
          const num = +value;
          if (!Number.isInteger(num) || num < 8 || num > 15) {
            throw new TypeError(
              `Invalid value for parameter "${key}": ${value}`
            );
          }
          value = num;
        } else if (

View on GitHub (pinned to c791e707ea)