{"record":{"id":"f4cc34cc4aa04611","repo":"NousResearch/hermes-agent","slug":"lsp-message-missing-content-length-headers-r","errorCode":null,"errorMessage":"LSP message missing Content-Length: {headers!r}","messagePattern":"LSP message missing Content-Length: (.+?)","errorType":"exception","errorClass":"LSPProtocolError","httpStatus":null,"severity":"error","filePath":"agent/lsp/protocol.py","lineNumber":109,"sourceCode":"        header_bytes += len(line)\n        if header_bytes > 8192:\n            raise LSPProtocolError(\n                \"LSP header block exceeded 8 KiB without terminator\"\n            )\n        line = line[:-2]  # strip CRLF\n        if not line:\n            break  # blank line ends header block\n        try:\n            key, _, value = line.decode(\"ascii\").partition(\":\")\n        except UnicodeDecodeError as e:\n            raise LSPProtocolError(f\"non-ASCII LSP header: {line!r}\") from e\n        if not key:\n            raise LSPProtocolError(f\"malformed LSP header line: {line!r}\")\n        headers[key.strip().lower()] = value.strip()\n\n    cl = headers.get(\"content-length\")\n    if cl is None:\n        raise LSPProtocolError(f\"LSP message missing Content-Length: {headers!r}\")\n    try:\n        n = int(cl)\n    except ValueError as e:\n        raise LSPProtocolError(f\"non-integer Content-Length: {cl!r}\") from e\n    if n < 0 or n > 64 * 1024 * 1024:  # 64 MiB sanity cap\n        raise LSPProtocolError(f\"unreasonable Content-Length: {n}\")\n\n    try:\n        body = await reader.readexactly(n)\n    except asyncio.IncompleteReadError as e:\n        raise LSPProtocolError(\n            f\"truncated LSP body: expected {n} bytes, got {len(e.partial)}\"\n        ) from e\n\n    try:\n        return json.loads(body.decode(\"utf-8\"))\n    except json.JSONDecodeError as e:\n        raise LSPProtocolError(f\"invalid JSON in LSP body: {e}\") from e","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/agent/lsp/protocol.py#L91-L127","documentation":"LSPProtocolError raised when a complete header block was parsed but contained no Content-Length header. Content-Length is mandatory in the LSP base protocol (there is no chunked encoding), so the parser cannot know how many body bytes to read and refuses to guess.","triggerScenarios":"A server that sends only Content-Type before the blank line, a JSON-RPC message written without framing (raw json.dumps + newline — common in hand-rolled servers), or stdout noise that happens to parse as colon-lines then a blank line.","commonSituations":"Custom/in-house 'LSP-like' servers skipping the base protocol; servers reading LSP but writing responses via a plain print(json); partially-implemented test doubles.","solutions":["If it is your server, frame every outbound message: headers 'Content-Length: <utf8 byte length>\\r\\n\\r\\n' followed by the JSON body — length must be the byte count, not the string length.","If it is a third-party server, file/upgrade — a server that omits Content-Length cannot talk LSP at all.","Verify no other process is multiplexed onto the server's stdout."],"exampleFix":"# before (server side)\nprint(json.dumps(message))  # client: missing Content-Length\n\n# after (server side)\nbody = json.dumps(message).encode(\"utf-8\")\nsys.stdout.buffer.write(f\"Content-Length: {len(body)}\\r\\n\\r\\n\".encode() + body)\nsys.stdout.buffer.flush()","handlingStrategy":"validation","validationCode":"# server-side: frame every message before writing it\ndef frame_message(msg: dict) -> bytes:\n    body = json.dumps(msg).encode(\"utf-8\")\n    return f\"Content-Length: {len(body)}\\r\\n\\r\\n\".encode(\"ascii\") + body","typeGuard":null,"tryCatchPattern":null,"preventionTips":["If you implement the server, always write Content-Length (byte length) headers — never print raw JSON.","Use existing framing helpers instead of hand-rolled writes.","Smoke-test any custom server against a reference LSP client before integration."],"tags":["lsp","protocol","framing"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}