websockets/ws · error · Error

Parameter " " must have only a single value

Error message

Parameter "${key}" must have only a single value

What it means

Thrown by `PerMessageDeflate.normalizeParams()` when a parameter appears more than once in a single extension configuration, i.e. its value array (produced by `extension.parse()` which collects repeats) has length > 1. RFC 7692 requires each parameter to occur at most once per offer, so duplicates are rejected.

Solutions

  1. Send each parameter at most once per extension offer.
  2. Generate the header with `extension.format()`, which never emits duplicates.
  3. Catch the error during the handshake and close with code 1002 (protocol error).

Example fix

// before — duplicated parameter
extension.parse('permessage-deflate; client_max_window_bits=10; client_max_window_bits=12');
pmd.normalizeParams(/* its output */);

// after — single value
extension.parse('permessage-deflate; client_max_window_bits=12');
Defensive patterns

Strategy: validation

Validate before calling

// Reject duplicate parameters before calling normalizeParams/accept.
function hasDuplicateParams(offer) {
  return Object.values(offer).some((v) => Array.isArray(v) && v.length > 1);
}
if (parsedOffers.some(hasDuplicateParams)) {
  abortHandshake(socket, 1002);
}

Try / catch

try {
  perMessageDeflate.accept(parsedOffers);
} catch (err) {
  if (/must have only a single value/.test(err.message)) {
    abortHandshake(socket, 1002);
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: A peer sends `Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits=10; client_max_window_bits=12`; after parsing this becomes `{ client_max_window_bits: ['10','12'] }` and `normalizeParams` throws. Triggered internally during `accept()`.

Common situations: A buggy client or proxy duplicates a parameter; a hand-crafted header with repeated keys; fuzzer input that stresses the handshake.

Related errors


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

Appendix: source

Thrown at lib/permessage-deflate.js:252

    }

    return params;
  }

  /**
   * Normalize parameters.
   *
   * @param {Array} configurations The extension negotiation offers/reponse
   * @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}`
            );
          }

View on GitHub (pinned to c791e707ea)