{"record":{"id":"cef4f884c2cf30e7","repo":"Hmbown/CodeWhale","slug":"json-rpc-line-exceeded-the-max-bytes-byte-limit","errorCode":null,"errorMessage":"JSON-RPC line exceeded the {max_bytes}-byte limit","messagePattern":"JSON-RPC line exceeded the (.+?)-byte limit","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/mcp/src/stdio_client.rs","lineNumber":239,"sourceCode":"/// `max_bytes`. On an oversized line the reader is intentionally abandoned;\n/// continuing after losing JSON-RPC framing would be unsafe.\npub(crate) fn read_bounded_line<R: BufRead>(\n    reader: &mut R,\n    max_bytes: usize,\n) -> io::Result<Option<String>> {\n    let mut line = Vec::new();\n    loop {\n        let available = reader.fill_buf()?;\n        if available.is_empty() {\n            if line.is_empty() {\n                return Ok(None);\n            }\n            break;\n        }\n\n        if let Some(newline) = available.iter().position(|byte| *byte == b'\\n') {\n            if line.len().saturating_add(newline) > max_bytes {\n                return Err(io::Error::new(\n                    io::ErrorKind::InvalidData,\n                    format!(\"JSON-RPC line exceeded the {max_bytes}-byte limit\"),\n                ));\n            }\n            line.extend_from_slice(&available[..newline]);\n            reader.consume(newline + 1);\n            break;\n        }\n\n        if line.len().saturating_add(available.len()) > max_bytes {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                format!(\"JSON-RPC line exceeded the {max_bytes}-byte limit\"),\n            ));\n        }\n        line.extend_from_slice(available);\n        let consumed = available.len();\n        reader.consume(consumed);","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/mcp/src/stdio_client.rs#L221-L257","documentation":"read_bounded_line enforces a per-line byte cap (max_bytes) on JSON-RPC frames read from the MCP server child's stdout so a misbehaving or malicious server cannot exhaust memory. When a newline is found and the accumulated line plus the bytes up to it would exceed max_bytes, it returns InvalidData with this message. The whole oversized line is discarded — the connection is treated as unusable.","triggerScenarios":"An MCP stdio server emits a single JSON-RPC message (up to and including its newline) longer than max_bytes; the error surfaces in spawn_with_timeouts while reading the handshake or any response.","commonSituations":"A server that pretty-prints or logs huge blobs on stdout instead of speaking line-delimited JSON-RPC; a non-MCP program (build noise, banners) launched as the server; a server stuck in a loop dumping data; max_bytes misconfigured far below real payload sizes (large tool results).","solutions":["Fix the MCP server to emit one compact JSON-RPC object per line and keep logs on stderr","Ensure the command in the MCP config actually launches the MCP server, not a wrapper that prints extra output","If legitimate payloads are large, raise the line-size limit in the client configuration","Capture the server's raw stdout once to identify what it is actually emitting"],"exampleFix":"// before: server prints diagnostics to stdout\nprintln!(\"loaded {} tools\", n); // pollutes JSON-RPC stream\n// after\neprintln!(\"loaded {} tools\", n); // stderr only","handlingStrategy":"validation","validationCode":"// smoke-test the server's stdout before wiring it up\nconst MAX_LINE: usize = 1 << 20; // match max_bytes\nproc.stdout.lines().take(1).for_each(|l|\n    assert!(l.unwrap().len() < MAX_LINE, \"server line exceeds limit\"));","typeGuard":null,"tryCatchPattern":"match client.call(tool, args) {\n    Err(e) if e.kind() == io::ErrorKind::InvalidData && e.to_string().contains(\"byte limit\") => {\n        eprintln!(\"MCP server emitted an oversized/non-protocol line; check its stdout\");\n        restart_server();\n    }\n    r => r,\n}","preventionTips":["Reserve stdout exclusively for line-delimited JSON-RPC; log to stderr","Smoke-test server startup output before production use","Keep legitimate payloads well under max_bytes or raise the limit deliberately","Never wrap the MCP server in scripts that echo to stdout"],"tags":["mcp","stdio","protocol","limit"],"backgroundTag":"payload-too-large","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}