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
- Re-run the handoff with a healthy stdout: a normal terminal or `| consumer` (BrokenPipe is already treated as a clean settlement).
- Check disk space and fd validity where stdout is redirected (`df`, `ls -l /proc/<pid>/fd/1`).
- 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
- Keep the pipe consumer alive until it has read the line (BrokenPipe is handled, other errors are not).
- Avoid redirecting handoff output to files on full filesystems.
- Treat the message as intentionally detail-free: never log the secret; debug via the consumer's exit code.
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
- external credential path must be absolute and lexically…
- external credential path must name a regular file
- refusing terminal output; pipe credential handoff to the…
- bundle URLs may not include credentials
- Codewhale-owned credential file DACL is not…
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)