{"record":{"id":"e62e302736470ab2","repo":"NousResearch/hermes-agent","slug":"malformed-lsp-header-line-line-r","errorCode":null,"errorMessage":"malformed LSP header line: {line!r}","messagePattern":"malformed LSP header line: (.+?)","errorType":"exception","errorClass":"LSPProtocolError","httpStatus":null,"severity":"error","filePath":"agent/lsp/protocol.py","lineNumber":104,"sourceCode":"                f\"unexpected EOF while reading LSP headers (partial={e.partial!r})\"\n            ) from e\n        # Defensive cap against a server streaming headers without ever\n        # emitting CRLF-CRLF.  Caps total header bytes at 8 KiB — a\n        # well-behaved server fits in well under 200 bytes.\n        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","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/agent/lsp/protocol.py#L86-L122","documentation":"LSPProtocolError raised when a decoded header line has no ':' separator — after stripping CRLF, partition(':') found an empty key. The base protocol requires 'Header-Name: value' lines, so a separator-free line means the server is emitting non-header content in the header region.","triggerScenarios":"A blank-but-not-empty line (e.g. only spaces — the parser only breaks on a truly empty line), a stray status line like 'Server ready' printed to stdout, or framing desync landing the parser mid-body.","commonSituations":"Servers or launch wrappers printing human-readable status/banners to stdout; a server writing LF-only line endings so CRLF stripping leaves residue; desync after a bad Content-Length.","solutions":["Eliminate all stdout output from the server and its launcher; route logs to stderr or a file.","Confirm the server emits strict CRLF line endings in the base protocol (try a different/older version if it is a server bug).","Reproduce the server's raw stdout (e.g. capture with a tee shim) to see exactly which line lacks the colon."],"exampleFix":"# capture the raw wire to diagnose which line is malformed\n# shim: stdio-tee.sh\n# #!/bin/sh\n# \"$@\" 2>>/tmp/lsp-server.log | tee /tmp/lsp-stdout.raw\nLSPClient(cmd=[\"/path/stdio-tee.sh\", \"pyright-langserver\", \"--stdio\"], ...)","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    msg = await read_message(reader)\nexcept LSPProtocolError as e:\n    if \"malformed LSP header\" in str(e):\n        capture_raw_stream_and_restart()  # tee stdout to a file, then fresh session\n    else:\n        raise","preventionTips":["Use a tee shim to capture the raw wire when diagnosing — you need the exact offending line.","Ensure the launcher/wrapper adds no banners or status lines to stdout.","Suspect framing desync whenever header-region errors appear; restart rather than resync."],"tags":["lsp","protocol","debugging"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}