jdx/mise · error
failed to read command {stream}: {err}
Error message
failed to read command {stream}: {err} What it means
While consuming hashed output streams, a read on the child's stdout or stderr pipe failed; cmd.rs surfaces it as `failed to read command <stream>: <err>` (stream identifies stdout/stderr, err is the underlying IO error). This usually means the pipe was broken or the OS returned an error mid-read.
Source
Thrown at src/cmd.rs:1395
let mut output_bytes = 0usize;
let mut consume = |output: HashedProcessOutput| -> Result<()> {
match output {
HashedProcessOutput::Stdout(bytes) => {
output_bytes = output_bytes.saturating_add(bytes.len());
if output_bytes > max_output_bytes {
bail!("command output exceeded {max_output_bytes} bytes");
}
stdout_hasher.update(&bytes);
}
HashedProcessOutput::Stderr(bytes) => {
output_bytes = output_bytes.saturating_add(bytes.len());
if output_bytes > max_output_bytes {
bail!("command output exceeded {max_output_bytes} bytes");
}
stderr_hasher.update(&bytes);
}
HashedProcessOutput::ReadError(stream, err) => {
bail!("failed to read command {stream}: {err}");
}
}
Ok(())
};
let mut status = None;
let mut wait = Box::pin(cp.wait());
loop {
tokio::select! {
result = &mut wait, if status.is_none() => {
status = Some(result?);
break;
}
output = rx.recv() => {
let Some(output) = output else {
status = Some(wait.await?);
break;
};
if let Err(err) = consume(output) {View on GitHub (pinned to afd2eddd3a)
Solutions
- Check the embedded IO error (`err`) for the root cause (EPIPE/EIO etc.).
- Re-run the command; transient pipe errors often disappear on retry.
- Investigate whether the child process crashes mid-execution (core dumps, dmesg, OOM killer logs).
- Check system resource limits (ulimit -n, pipe/memory pressure) in constrained environments.
Example fix
// before: child crashes mid-output mise run flaky-task # failed to read command stdout: Broken pipe (os error 32) // after: fix child or raise limits ulimit -n 4096 && mise run flaky-task
Defensive patterns
Strategy: retry
Validate before calling
# check resources before running ulimit -n; df -h /tmp; free -m
Try / catch
for attempt in 1 2 3; do mise run task && break || { [ $attempt -lt 3 ] && sleep 2; }; done Prevention
- Keep systems from killing children mid-run (watch OOM killer, sandbox limits).
- Raise fd limits in CI containers that run many parallel commands.
- Retry transient IO errors — they are often one-off.
When it happens
Trigger: execute_hashes_async reading a child's stdout/stderr when the OS read fails: the child killed its own end of the pipe abnormally, the fd was closed unexpectedly, or an OS-level IO error (EIO) occurred — distinct from clean EOF (Ok(None)), which breaks the loop normally.
Common situations: Child process crashing while output is still buffered; running out of file descriptors or pipe buffer resources; processes that close their stdio handles unexpectedly; sandboxed/limited CI environments killing processes.
Related errors
- a process it started kept its output open
- {} {err}
- timed out after {duration:?}
- command output exceeded {max_output_bytes} bytes
- command output pipes did not close within {pipe_drain_timeou
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/2a6af38b4c2eaa81.
Report an issue: GitHub.