{"record":{"id":"92ca0b6dbfb9a1a4","repo":"Hmbown/CodeWhale","slug":"stdio-transport-closed-stderr","errorCode":null,"errorMessage":"Stdio transport closed\n{stderr}","messagePattern":"Stdio transport closed\n(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/mcp/stdio.rs","lineNumber":325,"sourceCode":"        let mut line_bytes: Vec<u8> = Vec::new();\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 =\n                match read_line_capped(&mut self.reader, &mut line_bytes, MAX_MCP_RESPONSE_BYTES)\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                if let Some(stderr) = format_stderr_context(&self.stderr_tail).await {\n                    anyhow::bail!(\"Stdio transport closed\\n{stderr}\");\n                }\n                anyhow::bail!(\"Stdio transport closed\");\n            }\n\n            let line = String::from_utf8_lossy(&line_bytes);\n            let trimmed = line.trim();\n            if trimmed.is_empty() {\n                continue;\n            }\n\n            return Ok(trimmed.as_bytes().to_vec());\n        }\n    }\n\n    /// Send SIGTERM and wait up to `STDIO_SHUTDOWN_GRACE` for graceful exit,\n    /// then force termination and reap the child as the backstop.\n    async fn shutdown(&mut self) {\n        let mut child = self.child.lock().await;","sourceCodeStart":307,"sourceCodeEnd":343,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/mcp/stdio.rs#L307-L343","documentation":"The MCP server's stdout hit EOF (the child exited) and the stderr tail ring buffer had content, which is appended so the exit reason is visible. This is the classic 'MCP server failed at startup' error: the process was spawned, then terminated while printing a message to stderr.","triggerScenarios":"The configured command exits immediately after spawn: bad or missing flags, a required env var (API key) unset, missing interpreter (node/npx/python not on PATH), or a package version whose CLI changed.","commonSituations":"Wrong command/args in the MCP server entry; missing required arguments (server prints usage and exits); node not installed for npx-based servers; breaking CLI changes after a package upgrade.","solutions":["Read the stderr excerpt in the message — it is the server's own failure output","Copy the command and args from the config and run them manually; fix until the server starts and stays up","Ensure the runtime (node, python, uvx, docker) is installed and visible on the app's PATH","Declare any required env vars (API keys) in the server configuration"],"exampleFix":"// before: server exits with 'missing required argument: PATH' on stderr\ncommand: npx -y @modelcontextprotocol/server-filesystem\n\n// after: required argument supplied\ncommand: npx -y @modelcontextprotocol/server-filesystem /home/me/projects","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"```rust\nfn exited_with_stderr(msg: &str) -> bool {\n    msg.starts_with(\"Stdio transport closed\\n\")\n}\n```","tryCatchPattern":"```rust\nmatch stdio_transport.recv().await {\n    Err(e) if exited_with_stderr(&format!(\"{e:#}\")) => {\n        surface_stderr_tail(&e); // startup failure: show the server's reason\n        Err(e)\n    }\n    other => other.map(|f| f)?,\n}\n```","preventionTips":["Validate command/args by running them manually before adding the server","Declare required env vars (API keys) in the server entry","Pin package versions so CLI flag changes don't silently break startup"],"tags":["mcp","stdio","subprocess","startup"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}