{"record":{"id":"bc2a5589a3c316f6","repo":"Hmbown/CodeWhale","slug":"stdio-transport-read-error-err-n-stderr","errorCode":null,"errorMessage":"Stdio transport read error: {err}\\n{stderr}","messagePattern":"Stdio transport read error: (.+?)\\\\n(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/mcp/stdio.rs","lineNumber":340,"sourceCode":"            Err(_) => false,\n        }\n    }\n\n    async fn recv(&mut self) -> Result<Vec<u8>> {\n        loop {\n            // Bounded read: a server emitting a newline-free multi-GB \"line\"\n            // must not OOM us (read_line is unbounded).\n            let bytes = match read_line_capped(\n                &mut self.reader,\n                &mut self.pending_line,\n                MAX_MCP_RESPONSE_BYTES,\n            )\n            .await\n            {\n                Ok(b) => b,\n                Err(err) => {\n                    if let Some(stderr) = format_stderr_context(&self.stderr_tail).await {\n                        anyhow::bail!(\"Stdio transport read error: {err}\\n{stderr}\");\n                    }\n                    return Err(err.into());\n                }\n            };\n            if bytes == 0 {\n                // Let the stderr drain task catch up before snapshotting, and\n                // name the exit status: a reviewed plugin's stderr is never\n                // retained, so the status is the only reason the operator\n                // gets when the child dies before the handshake (#5916).\n                tokio::task::yield_now().await;\n                let exit = self.child.lock().await.try_wait().ok().flatten();\n                let exit = exit.map_or_else(String::new, |status| format!(\" ({status})\"));\n                if let Some(stderr) = format_stderr_context(&self.stderr_tail).await {\n                    anyhow::bail!(\"Stdio transport closed{exit}\\n{stderr}\");\n                }\n                anyhow::bail!(\"Stdio transport closed{exit}\");\n            }\n","sourceCodeStart":322,"sourceCodeEnd":358,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/mcp/stdio.rs#L322-L358","documentation":"The stdio MCP transport failed while reading from the child process's stdout. When a captured stderr tail is available it is appended to the error so the operator sees the child's own diagnostic output alongside the I/O error.","triggerScenarios":"recv() awaiting the next length-prefixed message from the child's stdout hits an I/O error — child crashed mid-write, pipe broken, descriptor closed, or the process was killed.","commonSituations":"MCP server binary panics or OOM-killed mid-response; child writes invalid data then dies; OS pipe buffer/EOF issues; spawning with a bad command leaves no reader.","solutions":["Read the embedded stderr tail — it usually contains the child's panic or error message.","Verify the MCP server command/args in config point to a working binary (run it manually).","Check the child isn't being killed by OOM or a resource limit.","Update or reinstall the MCP server package if the binary is corrupted."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// before spawning, ensure the command resolves\nwhich::which(&cfg.command).map_err(|_| format!(\"command not found: {}\", cfg.command))?;","typeGuard":null,"tryCatchPattern":"match transport.recv().await {\n    Err(e) if e.to_string().starts_with(\"Stdio transport read error\") => {\n        // stderr tail is embedded — surface it to the operator, then restart the child\n        log::error!(\"{e}\");\n        transport = StdioTransport::spawn(&cfg).await?;\n    }\n    other => other?,\n}","preventionTips":["Validate the MCP server command/args resolve before configuring them.","Watch child stderr continuously and alert on panics.","Set sane memory limits so the child isn't OOM-killed mid-response."],"tags":["mcp","stdio","io-error","subprocess"],"backgroundTag":"broken-pipe","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}