BloopAI/vibe-kanban · error

Failed to take child stderr

Error message

Failed to take child stderr

What it means

The third take: after spawn, the child's stderr handle must be piped so it can be forwarded to the SSH client. child.stderr.take() returns None when stderr was not set to Stdio::piped(), producing this error. Like the stdin/stdout variants, it signals broken internal command construction rather than a user-triggerable condition.

Source

Thrown at crates/embedded-ssh/src/handler.rs:106

            cmd.current_dir(home);
        }

        let mut child = cmd
            .spawn()
            .map_err(|e| anyhow::anyhow!("Failed to spawn stdio command: {e}"))?;

        let stdin = child
            .stdin
            .take()
            .ok_or_else(|| anyhow::anyhow!("Failed to take child stdin"))?;
        let stdout = child
            .stdout
            .take()
            .ok_or_else(|| anyhow::anyhow!("Failed to take child stdout"))?;
        let stderr = child
            .stderr
            .take()
            .ok_or_else(|| anyhow::anyhow!("Failed to take child stderr"))?;

        let (writer_tx, mut writer_rx) = mpsc::channel::<Vec<u8>>(64);
        tokio::spawn(async move {
            let mut stdin = stdin;
            while let Some(data) = writer_rx.recv().await {
                if stdin.write_all(&data).await.is_err() {
                    break;
                }
                if stdin.flush().await.is_err() {
                    break;
                }
            }
        });

        let handle = session.handle();
        let stdout_task = tokio::spawn(async move {
            let mut stdout = stdout;
            let mut buf = vec![0u8; 8192];

View on GitHub (pinned to 4deb7eca8f)

Solutions

  1. Ensure .stderr(Stdio::piped()) is set on the command before spawn.
  2. Check that no alternate construction path (e.g. PTY session) reuses this code with different Stdio config.
  3. Test that stderr output from a failing command is visible in the SSH client to confirm piping works.

Example fix

// before
cmd.stderr(Stdio::null());
// after
cmd.stderr(Stdio::piped());
Defensive patterns

Strategy: validation

Validate before calling

let mut cmd = Command::new(shell);
cmd.stdin(Stdio::piped());
cmd.stdout(Stdio::piped());
cmd.stderr(Stdio::piped()); // required, otherwise take() -> None
let mut child = cmd.spawn()?;

Prevention

When it happens

Trigger: child.stderr.take() returns None because the command lacks .stderr(Stdio::piped()) at build time in spawn_stdio_session.

Common situations: Seen only if the handler's command construction was altered (e.g. stderr inherited for debugging) or partially configured; not triggerable by SSH clients.

Related errors


AI-assisted analysis of BloopAI/vibe-kanban@4deb7eca8f (2026-08-29). Data as JSON: /api/errors/7f6e2677f791e600. Report an issue: GitHub.