{"record":{"id":"2780cfc465432b10","repo":"BloopAI/vibe-kanban","slug":"child-process-has-no-stdout","errorCode":null,"errorMessage":"Child process has no stdout","messagePattern":"Child process has no stdout","errorType":"exception","errorClass":"ExecutorError","httpStatus":null,"severity":"error","filePath":"crates/executors/src/executors/acp/harness.rs","lineNumber":203,"sourceCode":"        })\n    }\n\n    #[allow(clippy::too_many_arguments)]\n    async fn bootstrap_acp_connection(\n        child: &mut AsyncGroupChild,\n        cwd: PathBuf,\n        existing_session: Option<String>,\n        prompt: String,\n        exit_signal: Option<tokio::sync::oneshot::Sender<ExecutorExitResult>>,\n        session_namespace: String,\n        model: Option<String>,\n        mode: Option<String>,\n        approvals: Option<std::sync::Arc<dyn ExecutorApprovalService>>,\n        cancel: CancellationToken,\n    ) -> Result<(), ExecutorError> {\n        // Take child's stdio for ACP wiring\n        let orig_stdout = child.inner().stdout.take().ok_or_else(|| {\n            ExecutorError::Io(std::io::Error::new(\n                std::io::ErrorKind::NotFound,\n                \"Child process has no stdout\",\n            ))\n        })?;\n        let orig_stdin = child.inner().stdin.take().ok_or_else(|| {\n            ExecutorError::Io(std::io::Error::new(\n                std::io::ErrorKind::NotFound,\n                \"Child process has no stdin\",\n            ))\n        })?;\n\n        // Create a fresh stdout pipe for logs\n        let writer = crate::stdout_dup::create_stdout_pipe_writer(child)?;\n        let shared_writer = Arc::new(tokio::sync::Mutex::new(writer));\n        let (log_tx, mut log_rx) = mpsc::unbounded_channel::<String>();\n\n        // Spawn log -> stdout writer task\n        tokio::spawn(async move {","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/BloopAI/vibe-kanban/blob/4deb7eca8f381f7cbc1f9d15515a9ab8f8009053/crates/executors/src/executors/acp/harness.rs#L185-L221","documentation":"bootstrap_acp_connection rewires the executor child process's stdio to speak ACP (Agent Client Protocol). It takes ownership of the child's stdout; if the child was spawned without a piped stdout (piped to null, inherited, or already taken), this error is returned because the harness cannot attach the protocol transport.","triggerScenarios":"Calling bootstrap_acp_connection on a child process spawned with stdout not set to piped, or after stdout/stdin were already taken by another bootstrap attempt.","commonSituations":"Custom spawn configuration disabling piped stdio; double-bootstrapping the same child; spawning the agent with stdout redirected to a file or terminal in a wrapper script; executor config change (e.g. enabling ACP mode for an executor whose spawn code doesn't pipe stdio).","solutions":["Spawn the child with stdout (and stdin) piped — ensure Command::stdout(Stdio::piped()).","Verify bootstrap_acp_connection is called exactly once per child process.","Check the executor's spawn code path matches the ACP-enabled configuration (stderr-only piping is not enough).","Inspect any wrapper/shell script that redirects the agent's stdout away from the pipe."],"exampleFix":"// before\nlet mut cmd = Command::new(agent);\ncmd.stderr(Stdio::piped());\n// after\nlet mut cmd = Command::new(agent);\ncmd.stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::piped());","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"fn has_piped_stdio(child: &Child) -> bool {\n    child.stdout.is_some() && child.stdin.is_some()\n}\nif !has_piped_stdio(&child) {\n    anyhow::bail!(\"respawn agent with piped stdin/stdout before ACP bootstrap\");\n}","tryCatchPattern":"match bootstrap_acp_connection(...).await {\n    Err(ExecutorError::Io(e)) if e.kind() == ErrorKind::NotFound\n        && e.to_string().contains(\"no stdout\") => {\n        // respawn with Stdio::piped()\n    }\n    other => other,\n}","preventionTips":["Always spawn ACP agents with stdin/stdout piped.","Bootstrap the ACP harness exactly once per child.","Keep spawn configuration in sync with executor ACP settings."],"tags":["process","stdio","acp","executor"],"backgroundTag":"missing-child-stdio-pipe","analyzedSha":"4deb7eca8f381f7cbc1f9d15515a9ab8f8009053","analyzedAt":"2026-08-29T09:24:13.446Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}