Hmbown/CodeWhale · error

credential handoff could not write to stdout

Error message

credential handoff could not write to stdout

What it means

handoff_secret_line writes the resolved secret (as a single line) to the given stdout writer. A write failure that is not BrokenPipe (e.g. EIO, EBADF, disk-full on the pipe target) is a real error and is bailed with this generic message that deliberately omits OS details and the secret value, keeping the credential out of logs and error output.

Solutions

  1. Re-run the handoff with a healthy stdout: a normal terminal or `| consumer` (BrokenPipe is already treated as a clean settlement).
  2. Check disk space and fd validity where stdout is redirected (`df`, `ls -l /proc/<pid>/fd/1`).
  3. Inside containers/CI, ensure the pipe consumer stays alive long enough to read, and inspect the generic error at the OS level — the message intentionally hides errno details.

Example fix

// before
consumer --exiting-immediately < <(codewhale credential api-key xai)
// after
codewhale credential api-key xai > /tmp/keyline
consumer < /tmp/keyline
Defensive patterns

Strategy: try-catch

Validate before calling

if let Err(e) = writeln!(std::io::stdout(), "probe") {
    if e.kind() != std::io::ErrorKind::BrokenPipe {
        eprintln!("stdout is not writable: {}", e.kind());
    }
}

Try / catch

match run_handoff(...) {
    Err(e) if e.to_string() == "credential handoff could not write to stdout" => {
        eprintln!("check stdout target (disk space, closed fd) — error details are redacted by design");
    }
    other => other,
}

Prevention

When it happens

Trigger: writeln! to the stdout writer fails with an error kind other than BrokenPipe during `credential api-key`/handoff; raised in handoff_secret_line for the pipe/terminal consumers covered by its tests.

Common situations: Writing into a full or closed pseudo-terminal; redirecting handoff output to a file on a full disk; output fd closed or invalid in a sandboxed/containerized runner; downstream process died in a way that surfaces EIO rather than EPIPE.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/d69aa2ada7ab21d9. Report an issue: GitHub.

Appendix: source

Thrown at crates/cli/src/credential_handoff.rs:71

    resolved
        .api_key
        .filter(|value| !value.trim().is_empty())
        .context("no usable runtime-effective API key")
}

pub(crate) fn handoff_secret_line(
    writer: &mut impl Write,
    stdout_is_terminal: bool,
    resolve: impl FnOnce() -> Result<String>,
) -> Result<()> {
    prepare_stdout(stdout_is_terminal)?;
    let secret = Zeroizing::new(resolve().map_err(|_| anyhow::anyhow!("unavailable credential"))?);
    ensure!(!secret.trim().is_empty(), "credential handoff was empty");
    let written = writeln!(writer, "{}", secret.as_str());
    if written.is_ok() || written.is_err_and(|error| error.kind() == ErrorKind::BrokenPipe) {
        return Ok(());
    }
    bail!("credential handoff could not write to stdout")
}
#[cfg(test)]
mod tests;

View on GitHub (pinned to 73e0f67d83)