websockets/ws · error · Error
Parameter "${key}" must have only a single value
Error message
Parameter "${key}" must have only a single value What it means
Thrown by PerMessageDeflate.normalizeParams() (permessage-deflate.js:249-250) when a parameter key has more than one value in a single configuration object. The parser represents each parameter's value(s) as an array; if that array's length exceeds 1, the negotiation is rejected because permessage-deflate parameters are defined to have at most one value per RFC 7692.
Source
Thrown at lib/permessage-deflate.js:250
}
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 ae1de54330)
Solutions
- Inspect the raw Sec-WebSocket-Extensions header for any parameter that appears more than once within a single extension configuration and remove the duplicate.
- If calling normalizeParams()/accept() directly, ensure each configuration object has at most one value per parameter key.
- Fix the peer that generates the duplicated parameter.
- Rely on the ws internal handshake handler which catches this and aborts with HTTP 400 — ensure the malformed header is not bypassing it.
Example fix
// before — duplicated parameter in raw header const header = 'permessage-deflate; client_max_window_bits=10; client_max_window_bits=12'; // after const header = 'permessage-deflate; client_max_window_bits=10';
Defensive patterns
Strategy: validation
Validate before calling
// Before calling accept/normalizeParams, ensure no parameter has multiple values
function hasDuplicateParams(offers) {
return offers.some((config) =>
Object.values(config).some((val) => Array.isArray(val) && val.length > 1))
);
}
if (!hasDuplicateParams(parsedOffers)) {
perMessageDeflate.accept(parsedOffers);
} Try / catch
try {
perMessageDeflate.accept(offers);
} catch (err) {
if (err.message.includes('must have only a single value')) {
console.warn('Duplicate parameter in offer — rejecting negotiation:', err.message);
} else {
throw err;
}
} Prevention
- Ensure the Sec-WebSocket-Extensions header does not repeat any parameter within a single extension configuration.
- When building offers programmatically, use unique keys.
- Rely on the ws internal handshake handler to catch this and return HTTP 400 — do not bypass it.
- Validate parsed offers for duplicate-value arrays before calling accept().
When it happens
Trigger: normalizeParams() is called (internally via accept()) with a configuration where one parameter maps to an array of length > 1. This happens when extension.parse() produces a parameter that appears multiple times in the same configuration segment, e.g. the raw header 'permessage-deflate; client_max_window_bits=10; client_max_window_bits=12' results in client_max_window_bits having two values [10, 12].
Common situations: A non-compliant client or server sends a Sec-WebSocket-Extensions header with a duplicated parameter in the same offer. A test fixture or hand-crafted offer object contains repeated keys. A proxy duplicates a parameter during header manipulation.
Related errors
- None of the extension offers can be accepted
- Unexpected parameter "client_no_context_takeover"
- Unexpected or invalid parameter "client_max_window_bits"
- Invalid value for parameter "${key}": ${value}
- Unknown parameter "${key}"
AI-assisted analysis of websockets/ws@ae1de54330 (2026-08-03).
Data as JSON: /data/errors/d114715b4c2bde20.json.
Report an issue: GitHub.