websockets/ws · error · SyntaxError

Unexpected character at index

Error message

Unexpected character at index ${i}

What it means

Thrown by `extension.parse()` while parsing the `Sec-WebSocket-Extensions` header (RFC 6455 §9.1). At this point the parser expects an extension name token (no name has started yet, `extensionName === undefined`) but it hit a `;` (0x3b) or `,` (0x2c) separator with `start === -1`, meaning the separator appeared before any token characters were read — e.g. the header begins with a separator, or two separators appear back-to-back at the start. The index `i` in the message is the byte offset of the offending character.

Solutions

  1. Inspect the offending header at the reported index and strip/escape the leading separator.
  2. Do not hand-build the header; produce it with `extension.format()` which always yields syntactically valid output.
  3. If the value comes from an untrusted peer, wrap the `accept()`/`parse()` handshake call in try/catch and fail the connection with a 1002 protocol error.

Example fix

// before
const offers = extension.parse(';permessage-deflate');

// after
const offers = extension.parse('permessage-deflate');
Defensive patterns

Strategy: try-catch

Try / catch

const { parse } = require('ws/lib/extension');
try {
  const offers = parse(header);
} catch (err) {
  if (err instanceof SyntaxError) {
    // Malformed Sec-WebSocket-Extensions header — fail the handshake.
    socket.write(Buffer.from([0x88, 0x02, 0x03, 0xea])); // close 1002
    socket.destroy();
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling `extension.parse(';permessage-deflate')`, `extension.parse(',permessage-deflate')`, or any header where a `;`/`,` appears before the first extension-name token. The library calls this internally when negotiating `permessage-deflate` against a malformed peer header.

Common situations: A buggy client/server sends a hand-crafted `Sec-WebSocket-Extensions` value with a leading separator; a proxy rewrites the header and injects a stray `;`; manual testing with a malformed header string.

Related errors


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

Appendix: source

Thrown at lib/extension.js:53

  let start = -1;
  let code = -1;
  let end = -1;
  let i = 0;

  for (; i < header.length; i++) {
    code = header.charCodeAt(i);

    if (extensionName === undefined) {
      if (end === -1 && tokenChars[code] === 1) {
        if (start === -1) start = i;
      } else if (
        i !== 0 &&
        (code === 0x20 /* ' ' */ || code === 0x09) /* '\t' */
      ) {
        if (end === -1 && start !== -1) end = i;
      } else if (code === 0x3b /* ';' */ || code === 0x2c /* ',' */) {
        if (start === -1) {
          throw new SyntaxError(`Unexpected character at index ${i}`);
        }

        if (end === -1) end = i;
        const name = header.slice(start, end);
        if (code === 0x2c) {
          push(offers, name, params);
          params = Object.create(null);
        } else {
          extensionName = name;
        }

        start = end = -1;
      } else {
        throw new SyntaxError(`Unexpected character at index ${i}`);
      }
    } else if (paramName === undefined) {
      if (end === -1 && tokenChars[code] === 1) {
        if (start === -1) start = i;

View on GitHub (pinned to c791e707ea)