{"record":{"id":"0924431b46bfcfbc","repo":"ultraworkers/claw-code","slug":"mcp-stdio-stream-closed-while-reading-headers-092443","errorCode":null,"errorMessage":"MCP stdio stream closed while reading headers","messagePattern":"MCP stdio stream closed while reading headers","errorType":"exception","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"rust/crates/runtime/src/mcp_stdio.rs","lineNumber":1241,"sourceCode":"        let mut buffer = vec![0_u8; 4096];\n        let read = self.stdout.read(&mut buffer).await?;\n        buffer.truncate(read);\n        Ok(buffer)\n    }\n\n    pub async fn write_frame(&mut self, payload: &[u8]) -> io::Result<()> {\n        let encoded = encode_frame(payload);\n        self.write_all(&encoded).await?;\n        self.flush().await\n    }\n\n    pub async fn read_frame(&mut self) -> io::Result<Vec<u8>> {\n        let mut content_length = None;\n        loop {\n            let mut line = String::new();\n            let bytes_read = self.stdout.read_line(&mut line).await?;\n            if bytes_read == 0 {\n                return Err(io::Error::new(\n                    io::ErrorKind::UnexpectedEof,\n                    \"MCP stdio stream closed while reading headers\",\n                ));\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        }","sourceCodeStart":1223,"sourceCodeEnd":1259,"githubUrl":"https://github.com/ultraworkers/claw-code/blob/08106b0c3771ef5b4a5aa176acccd460e88b7325/rust/crates/runtime/src/mcp_stdio.rs#L1223-L1259","documentation":"Client-side `McpStdioProcess::read_frame` (runtime/src/mcp_stdio.rs:1241): EOF (0 bytes from read_line) while still inside the Content-Length header loop of an LSP-style frame on the server's stdout — the server died mid-frame. Note this loop only breaks on the EXACT string `\"\\r\\n\"`; a server that terminates its header block with a bare `\"\\n\"` never breaks, reads to EOF, and produces this same error despite 'complete' framing.","triggerScenarios":"Server process crashing after writing partial headers; server killed mid-response; a server emitting LF-only line endings in its framing (bare `\\n` blank line does not terminate the header loop here, unlike the server-side reader which accepts both `\\r\\n` and `\\n`).","commonSituations":"Debugging homegrown MCP servers that use `\\n` framing; servers OOM-killed while streaming a large tools/list response; OOM or panic mid-write.","solutions":["Check the server's stderr and exit status for the crash cause; fix the crash first.","If you author the server, emit strict CRLF (`\\r\\n\\r\\n` after headers) — LF-only framing is not recognized by this reader.","Handle the error by restarting or disabling the server connection, not by retrying the same read."],"exampleFix":"# before (server writes LF-only framing)\nprintf 'Content-Length: 18\\n\\n{\"jsonrpc\":\"2.0\"...}'   # client hangs, then: stream closed while reading headers\n\n# after\nprintf 'Content-Length: 18\\r\\n\\r\\n{\"jsonrpc\":\"2.0\"...}'","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"match process.read_frame().await {\n    Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => {\n        // server died mid-header (or used bare-\\n framing): mark server unhealthy,\n        // log stderr, restart or disable the connection\n    }\n    other => other,\n}","preventionTips":["If you author the server: terminate header blocks with CRLF `\\r\\n\\r\\n` — this reader ignores bare `\\n`","Write frames atomically (single write, then flush)","Capture the child's stderr so mid-frame crashes are diagnosable"],"tags":["mcp","stdio","framing","eof"],"backgroundTag":"unexpected-eof","analyzedSha":"08106b0c3771ef5b4a5aa176acccd460e88b7325","analyzedAt":"2026-08-18T00:29:38.590Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}