NousResearch/hermes-agent · error · LSPProtocolError
LSP message missing Content-Length
Error message
LSP message missing Content-Length: {headers!r} What it means
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.
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.
Example fix
# before (server side)
print(json.dumps(message)) # client: missing Content-Length
# after (server side)
body = json.dumps(message).encode("utf-8")
sys.stdout.buffer.write(f"Content-Length: {len(body)}\r\n\r\n".encode() + body)
sys.stdout.buffer.flush() Defensive patterns
Strategy: validation
Validate before calling
# server-side: frame every message before writing it
def frame_message(msg: dict) -> bytes:
body = json.dumps(msg).encode("utf-8")
return f"Content-Length: {len(body)}\r\n\r\n".encode("ascii") + body Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- non-integer Content-Length
- unreasonable Content-Length
- LSP header block exceeded 8 KiB without terminator
- malformed LSP header line
- non-ASCII LSP header
AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14).
Data as JSON: /api/errors/f4cc34cc4aa04611.
Report an issue: GitHub.
Appendix: source
Thrown at agent/lsp/protocol.py:109
header_bytes += len(line)
if header_bytes > 8192:
raise LSPProtocolError(
"LSP header block exceeded 8 KiB without terminator"
)
line = line[:-2] # strip CRLF
if not line:
break # blank line ends header block
try:
key, _, value = line.decode("ascii").partition(":")
except UnicodeDecodeError as e:
raise LSPProtocolError(f"non-ASCII LSP header: {line!r}") from e
if not key:
raise LSPProtocolError(f"malformed LSP header line: {line!r}")
headers[key.strip().lower()] = value.strip()
cl = headers.get("content-length")
if cl is None:
raise LSPProtocolError(f"LSP message missing Content-Length: {headers!r}")
try:
n = int(cl)
except ValueError as e:
raise LSPProtocolError(f"non-integer Content-Length: {cl!r}") from e
if n < 0 or n > 64 * 1024 * 1024: # 64 MiB sanity cap
raise LSPProtocolError(f"unreasonable Content-Length: {n}")
try:
body = await reader.readexactly(n)
except asyncio.IncompleteReadError as e:
raise LSPProtocolError(
f"truncated LSP body: expected {n} bytes, got {len(e.partial)}"
) from e
try:
return json.loads(body.decode("utf-8"))
except json.JSONDecodeError as e:
raise LSPProtocolError(f"invalid JSON in LSP body: {e}") from eView on GitHub (pinned to c896c09c42)