{"record":{"id":"0a6f40068860f199","repo":"websockets/ws","slug":"unexpected-end-of-input-0a6f40","errorCode":null,"errorMessage":"Unexpected end of input","messagePattern":"Unexpected end of input","errorType":"exception","errorClass":"SyntaxError","httpStatus":null,"severity":"warning","filePath":"lib/subprotocol.js","lineNumber":49,"sourceCode":"      }\n\n      if (end === -1) end = i;\n\n      const protocol = header.slice(start, end);\n\n      if (protocols.has(protocol)) {\n        throw new SyntaxError(`The \"${protocol}\" subprotocol is duplicated`);\n      }\n\n      protocols.add(protocol);\n      start = end = -1;\n    } else {\n      throw new SyntaxError(`Unexpected character at index ${i}`);\n    }\n  }\n\n  if (start === -1 || end !== -1) {\n    throw new SyntaxError('Unexpected end of input');\n  }\n\n  const protocol = header.slice(start, i);\n\n  if (protocols.has(protocol)) {\n    throw new SyntaxError(`The \"${protocol}\" subprotocol is duplicated`);\n  }\n\n  protocols.add(protocol);\n  return protocols;\n}\n\nmodule.exports = { parse };\n","sourceCodeStart":31,"sourceCodeEnd":63,"githubUrl":"https://github.com/websockets/ws/blob/c791e707eab3c13dd9a261d2479c3cc4a49a6fed/lib/subprotocol.js#L31-L63","documentation":"Thrown by subprotocol.parse() at subprotocol.js:48-49 after the loop ends, when the header is structurally incomplete. Two cases: (a) start === -1, meaning no token was ever started (empty header or whitespace-only header), or (b) end !== -1, meaning a token was terminated by whitespace but the header ended without a final token or comma (e.g. trailing space, or a header like 'chat ').","triggerScenarios":"A client sends an empty Sec-WebSocket-Protocol header (or just spaces/tabs), or a header that ends with trailing whitespace after a token like 'chat '. After the loop, start === -1 (nothing started) or end !== -1 (token was whitespace-terminated but input ended) triggers the error at subprotocol.js:49.","commonSituations":"A header value of '' or '   ' (whitespace only); a trailing-space bug when constructing headers; a proxy that strips content but leaves the header field present; an intermediate layer that sets the header to a space.","solutions":["Ensure the Sec-WebSocket-Protocol header contains at least one non-empty token and does not end with whitespace.","On the server, handleUpgrade already catches this and responds with HTTP 400 — no additional handling needed for normal usage.","If calling parse() directly, wrap in try/catch and reject malformed/empty headers."],"exampleFix":"// before\nws = new WebSocket(url, ' ');\n\n// after — omit the header or provide a real token\nws = new WebSocket(url, 'chat');","handlingStrategy":"try-catch","validationCode":"function isValidProtocolHeader(header) {\n  if (typeof header !== 'string') return false;\n  const trimmed = header.trim();\n  if (trimmed.length === 0) return false;\n  try { require('ws/lib/subprotocol').parse(trimmed); return true; }\n  catch { return false; }\n}","typeGuard":"function isNonEmptyProtocolHeader(header) {\n  return typeof header === 'string' && header.trim().length > 0;\n}","tryCatchPattern":"try {\n  protocols = subprotocol.parse(secWebSocketProtocol);\n} catch (err) {\n  // empty/whitespace-only or structurally incomplete header\n  abortHandshake(socket, 400);\n  return;\n}","preventionTips":["Never send an empty or whitespace-only Sec-WebSocket-Protocol header; omit the header instead.","Trim trailing whitespace when constructing header values.","Wrap any direct call to subprotocol.parse() in try/catch and reject on failure."],"tags":["websocket","subprotocol","header-parsing","rfc6455","validation"],"backgroundTag":null,"analyzedSha":"c791e707eab3c13dd9a261d2479c3cc4a49a6fed","analyzedAt":"2026-08-06T19:07:51.047Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}