websockets/ws · error · SyntaxError

Unexpected end of input

Error message

Unexpected end of input

What it means

Thrown by extension.parse() at end-of-input (extension.js:150-151) when the final state is invalid: either start is -1 (the header ended right after a separator with no trailing token), inQuotes is still true (an unclosed double-quoted string), or the last character was whitespace (trailing space/tab). All three indicate the header is truncated or incomplete per RFC 6455 §9.1.

Source

Thrown at lib/extension.js:151

          mustUnescape = false;
        }
        push(params, paramName, value);
        if (code === 0x2c) {
          push(offers, extensionName, params);
          params = Object.create(null);
          extensionName = undefined;
        }

        paramName = undefined;
        start = end = -1;
      } else {
        throw new SyntaxError(`Unexpected character at index ${i}`);
      }
    }
  }

  if (start === -1 || inQuotes || code === 0x20 || code === 0x09) {
    throw new SyntaxError('Unexpected end of input');
  }

  if (end === -1) end = i;
  const token = header.slice(start, end);
  if (extensionName === undefined) {
    push(offers, token, params);
  } else {
    if (paramName === undefined) {
      push(params, token, true);
    } else if (mustUnescape) {
      push(params, paramName, token.replace(/\\/g, ''));
    } else {
      push(params, paramName, token);
    }
    push(offers, extensionName, params);
  }

  return offers;

View on GitHub (pinned to ae1de54330)

Solutions

  1. Check whether the header ends with a separator (';'/',') and remove the trailing separator, or append the missing token.
  2. If a quoted value is unterminated, add the closing '"'.
  3. Remove trailing whitespace from the header value.
  4. If the truncation comes from the network/peer, investigate packet fragmentation or proxy modification.

Example fix

// before
const offers = WebSocket.extension.parse('permessage-deflate; x="abc');

// after — close the quoted string
const offers = WebSocket.extension.parse('permessage-deflate; x="abc"');
Defensive patterns

Strategy: try-catch

Validate before calling

// Reject truncated headers: trailing separators, trailing whitespace, unclosed quotes
function isCompleteHeader(header) {
  const trimmed = header.trim();
  if (/[;,]$/.test(trimmed)) return false;
  if (trimmed.endsWith(' ') || trimmed.endsWith('\t')) return false;
  const quoteCount = (trimmed.match(/"/g) || []).length;
  if (quoteCount % 2 !== 0) return false;
  return true;
}

if (isCompleteHeader(header)) {
  const offers = WebSocket.extension.parse(header);
}

Try / catch

try {
  const offers = WebSocket.extension.parse(header);
} catch (err) {
  if (err instanceof SyntaxError && err.message === 'Unexpected end of input') {
    console.warn('Truncated extensions header:', header);
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: extension.parse() is called with a header that ends prematurely: 'permessage-deflate;' (trailing separator, start is -1 at end), 'permessage-deflate; x="abc' (unclosed quote, inQuotes is true), or 'permessage-deflate ' (trailing whitespace, last char was space).

Common situations: A truncated Sec-WebSocket-Extensions header from a network read that cut off mid-value. A developer's string-building code forgets to append the closing quote or final token. A header value that was trimmed or corrupted by a proxy.

Related errors


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