{"record":{"id":"3b452ce4584fdd52","repo":"ultraworkers/claw-code","slug":"missing-content-length-header-3b452c","errorCode":null,"errorMessage":"missing Content-Length header","messagePattern":"missing Content-Length header","errorType":"validation","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"rust/crates/runtime/src/mcp_stdio.rs","lineNumber":1262,"sourceCode":"                ));\n            }\n            if line == \"\\r\\n\" {\n                break;\n            }\n            let header = line.trim_end_matches(['\\r', '\\n']);\n            if let Some((name, value)) = header.split_once(':') {\n                if name.trim().eq_ignore_ascii_case(\"Content-Length\") {\n                    let parsed = value\n                        .trim()\n                        .parse::<usize>()\n                        .map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))?;\n                    content_length = Some(parsed);\n                }\n            }\n        }\n\n        let content_length = content_length.ok_or_else(|| {\n            io::Error::new(io::ErrorKind::InvalidData, \"missing Content-Length header\")\n        })?;\n        let mut payload = vec![0_u8; content_length];\n        self.stdout.read_exact(&mut payload).await?;\n        Ok(payload)\n    }\n\n    pub async fn write_jsonrpc_message<T: Serialize>(&mut self, message: &T) -> io::Result<()> {\n        let body = serde_json::to_vec(message)\n            .map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))?;\n        self.write_frame(&body).await\n    }\n\n    pub async fn read_jsonrpc_message<T: DeserializeOwned>(&mut self) -> io::Result<T> {\n        let payload = self.read_frame().await?;\n        serde_json::from_slice(&payload)\n            .map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))\n    }\n","sourceCodeStart":1244,"sourceCodeEnd":1280,"githubUrl":"https://github.com/ultraworkers/claw-code/blob/08106b0c3771ef5b4a5aa176acccd460e88b7325/rust/crates/runtime/src/mcp_stdio.rs#L1244-L1280","documentation":"Client-side `McpStdioProcess::read_frame` (runtime/src/mcp_stdio.rs:1262): the header block on the server's stdout terminated (blank `\\r\\n` line) without any parseable Content-Length header. Lines without a ':' are ignored, so non-protocol output followed by a blank line lands here. `ErrorKind::InvalidData`.","triggerScenarios":"The MCP server logging to STDOUT (a log line, then a blank line) corrupts the frame stream; a server implementing newline-delimited JSON instead of LSP-style Content-Length framing; a startup banner printed to stdout before the first frame; a misspelled Content-Length header name.","commonSituations":"Python/Node MCP servers whose logger writes to stdout by default; debug prints left in a forked server; versions where the server switched framing mode; wrappers like `npx` banners.","solutions":["Configure the server to log to stderr only (most MCP SDKs default to stderr; redirect any stdout logging).","Use a server that implements Content-Length framing per the MCP stdio spec.","Reproduce manually: run the server command and inspect stdout vs stderr to find the stray output."],"exampleFix":"# before (server logs to stdout)\nlogger = logging.getLogger(); logger.addHandler(logging.StreamHandler(sys.stdout))\n\n# after (log to stderr so stdout carries only framed JSON-RPC)\nlogger.addHandler(logging.StreamHandler(sys.stderr))","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match process.read_frame().await {\n    Err(e) if e.kind() == io::ErrorKind::InvalidData\n        && e.to_string().contains(\"missing Content-Length\") => {\n        // server is polluting stdout (logs/NDJSON): fix server to use stderr + framed output\n    }\n    other => other,\n}","preventionTips":["Route ALL server logging to stderr; stdout must carry only framed JSON-RPC","Don't add print/banner/debug statements to stdout in MCP servers","Reproduce by running the server command and diffing stdout vs stderr"],"tags":["mcp","stdio","framing","content-length"],"backgroundTag":"missing-content-length-header","analyzedSha":"08106b0c3771ef5b4a5aa176acccd460e88b7325","analyzedAt":"2026-08-18T00:29:38.590Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}