websockets/ws · error · Error

Unexpected parameter "client_no_context_takeover"

Error message

Unexpected parameter "client_no_context_takeover"

What it means

Thrown by PerMessageDeflate.acceptAsClient() (permessage-deflate.js:213-217) when the client has explicitly set clientNoContextTakeover to false (disabling context takeover) but the server's negotiation response includes the client_no_context_takeover parameter. This is a protocol conflict: the client refused context takeover, yet the server insists on it.

Source

Thrown at lib/permessage-deflate.js:217

    return accepted;
  }

  /**
   * Accept the extension negotiation response.
   *
   * @param {Array} response The extension negotiation response
   * @return {Object} Accepted configuration
   * @private
   */
  acceptAsClient(response) {
    const params = response[0];

    if (
      this._options.clientNoContextTakeover === false &&
      params.client_no_context_takeover
    ) {
      throw new Error('Unexpected parameter "client_no_context_takeover"');
    }

    if (!params.client_max_window_bits) {
      if (typeof this._options.clientMaxWindowBits === 'number') {
        params.client_max_window_bits = this._options.clientMaxWindowBits;
      }
    } else if (
      this._options.clientMaxWindowBits === false ||
      (typeof this._options.clientMaxWindowBits === 'number' &&
        params.client_max_window_bits > this._options.clientMaxWindowBits)
    ) {
      throw new Error(
        'Unexpected or invalid parameter "client_max_window_bits"'
      );
    }

    return params;
  }

View on GitHub (pinned to ae1de54330)

Solutions

  1. Remove clientNoContextTakeover: false from the client options (or set it to true/undefined) to allow the server to request context takeover disabling.
  2. Reconfigure the server to not send client_no_context_takeover in its response when the client doesn't offer it.
  3. Set perMessageDeflate: false on the client to skip compression negotiation entirely.
  4. Understand the semantics: clientNoContextTakeover: true means 'request the server to disable'; false means 'reject if the server tries to set it'.

Example fix

// before
const ws = new WebSocket('ws://host', {
  perMessageDeflate: { clientNoContextTakeover: false }
});

// after — allow the server to request context takeover disabling
const ws = new WebSocket('ws://host', {
  perMessageDeflate: { clientNoContextTakeover: true }
});
Defensive patterns

Strategy: try-catch

Validate before calling

// Before connecting, ensure clientNoContextTakeover is not set to false
// if the server is known to send client_no_context_takeover
function validateClientDeflateOpts(opts) {
  if (opts && opts.clientNoContextTakeover === false) {
    console.warn('clientNoContextTakeover: false will reject servers that send client_no_context_takeover');
    return false;
  }
  return true;
}

Try / catch

try {
  perMessageDeflate.accept(serverResponse);
} catch (err) {
  if (err.message.includes('client_no_context_takeover')) {
    // Retype or disable compression
    console.error('Server response incompatible with client options:', err.message);
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: A WebSocket client is created with `{ perMessageDeflate: { clientNoContextTakeover: false } }` and connects to a server whose permessage-deflate response advertises client_no_context_takeover. During the client's accept() call, this mismatch is detected and the error is thrown.

Common situations: A client explicitly disables context takeover for memory reasons but connects to a server that always sends client_no_context_takeover in its response. A misconfigured or non-compliant server ignores the client's offer terms. A developer sets clientNoContextTakeover: false thinking it requests disabling, when actually false means 'do not allow the server to request it'.

Related errors


AI-assisted analysis of websockets/ws@ae1de54330 (2026-08-03). Data as JSON: /data/errors/38448e5ee28ba2d6.json. Report an issue: GitHub.