NousResearch/hermes-agent · error · LSPProtocolError

unreasonable Content-Length: {n}

Error message

unreasonable Content-Length: {n}

What it means

LSPProtocolError raised by the sanity cap on Content-Length: the parsed integer is negative or exceeds 64 MiB. Legitimate LSP messages are at most a few MB (huge diagnostics batches), so a value in that range means the length is corrupt — reading it would attempt a multi-gigabyte allocation or a negative read.

Source

Thrown at agent/lsp/protocol.py:115

        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 e
    except UnicodeDecodeError as e:
        raise LSPProtocolError(f"non-UTF-8 LSP body: {e}") from e


def make_request(req_id: int, method: str, params: Any) -> dict:
    """Build a JSON-RPC 2.0 request envelope."""

View on GitHub (pinned to c896c09c42)

Solutions

  1. Restart the session — a desynced stream rarely recovers; a fresh client/server pair resets framing.
  2. Update the server if the bug is known (check the server's issue tracker for Content-Length corruption).
  3. Verify the message that triggers it: if a genuinely huge diagnostic batch exceeds 64 MiB (extremely unlikely), chunk server-side work; otherwise treat it as corruption.
Defensive patterns

Strategy: fallback

Validate before calling

# server-side: sanity-check before writing the header
MAX = 64 * 1024 * 1024

def frame(msg: dict) -> bytes:
    body = json.dumps(msg).encode("utf-8")
    assert len(body) <= MAX, "message exceeds LSP sanity cap; chunk it"
    return f"Content-Length: {len(body)}\r\n\r\n".encode() + body

Try / catch

try:
    msg = await read_message(reader)
except LSPProtocolError as e:
    if "unreasonable Content-Length" in str(e):
        restart_session()  # desync/corruption; rebuild client+server
    else:
        raise

Prevention

When it happens

Trigger: Corrupted length from a crashed/desynced server; a server with an integer overflow computing length; the parser misaligned reading body bytes as a header after a previous message's length was wrong.

Common situations: Same family as other framing errors: stdout pollution, locale-formatted lengths, or a server bug in byte counting (using character count on non-ASCII JSON inflates nothing but using arbitrary offsets does).

Related errors


AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14). Data as JSON: /api/errors/5634d7021a0fb957. Report an issue: GitHub.