websockets/ws · warning · SyntaxError
Unexpected end of input
Error message
Unexpected end of input
What it means
Thrown by subprotocol.parse() after the loop ends (lib/subprotocol.js:48-50) when start === -1 (no protocol token was ever started, i.e. the header was empty or only whitespace/commas) OR when end !== -1 (a token was terminated by whitespace but the input ended there, i.e. trailing whitespace). Both are malformed per the grammar. On the server this becomes an HTTP 400 'Invalid Sec-WebSocket-Protocol header'.
Source
Thrown at lib/subprotocol.js:49
}
if (end === -1) end = i;
const protocol = header.slice(start, end);
if (protocols.has(protocol)) {
throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`);
}
protocols.add(protocol);
start = end = -1;
} else {
throw new SyntaxError(`Unexpected character at index ${i}`);
}
}
if (start === -1 || end !== -1) {
throw new SyntaxError('Unexpected end of input');
}
const protocol = header.slice(start, i);
if (protocols.has(protocol)) {
throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`);
}
protocols.add(protocol);
return protocols;
}
module.exports = { parse };
View on GitHub (pinned to ae1de54330)
Solutions
- Do not send the Sec-WebSocket-Protocol header at all if there are no protocols to offer.
- Trim trailing/leading whitespace from the header value before sending.
- On the server, listen for 'wsClientError' to observe these clients instead of treating them as fatal.
Example fix
// before
req.setHeader('Sec-WebSocket-Protocol', protocols.join(',') + ' ');
// after
req.setHeader('Sec-WebSocket-Protocol', protocols.join(',').trim()); Defensive patterns
Strategy: validation
Validate before calling
function buildProtocolHeader(protocols) {
const header = [...new Set(protocols.filter(Boolean))].join(',').trim();
return header.length ? header : undefined; // omit header when empty
} Type guard
function isNonEmptyTrimmedHeader(header) {
return typeof header === 'string' && header.trim().length > 0 && header === header.trim();
} Try / catch
wss.on('wsClientError', (err, socket, req) => {
if (/Unexpected end of input/.test(err.message)) {
// empty or trailing-whitespace Sec-WebSocket-Protocol; default 400 already sent
}
}); Prevention
- Do not send Sec-WebSocket-Protocol when the protocol list is empty.
- Trim leading/trailing whitespace from the header value before sending.
- Watch for middleware that leaves an empty header after stripping content.
When it happens
Trigger: A client sends an empty Sec-WebSocket-Protocol header (e.g. '') or a header ending in trailing whitespace like 'chat '. The parser cannot finalize a token and throws SyntaxError('Unexpected end of input').
Common situations: Client libraries that set the header unconditionally even when no protocols are configured; trailing-whitespace bugs from string concatenation; proxies that strip content but leave the empty header.
Related errors
- Unexpected character at index ${i}
- The "${protocol}" subprotocol is duplicated
- Unexpected character at index ${i}
- Unexpected end of input
- None of the extension offers can be accepted
AI-assisted analysis of websockets/ws@ae1de54330 (2026-08-03).
Data as JSON: /data/errors/0a6f40068860f199.json.
Report an issue: GitHub.