{"record":{"id":"2a6af38b4c2eaa81","repo":"jdx/mise","slug":"failed-to-read-command-stream-err","errorCode":null,"errorMessage":"failed to read command {stream}: {err}","messagePattern":"failed to read command (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmd.rs","lineNumber":1405,"sourceCode":"        let mut output_bytes = 0usize;\n        let mut consume = |output: HashedProcessOutput| -> Result<()> {\n            match output {\n                HashedProcessOutput::Stdout(bytes) => {\n                    output_bytes = output_bytes.saturating_add(bytes.len());\n                    if output_bytes > max_output_bytes {\n                        bail!(\"command output exceeded {max_output_bytes} bytes\");\n                    }\n                    stdout_hasher.update(&bytes);\n                }\n                HashedProcessOutput::Stderr(bytes) => {\n                    output_bytes = output_bytes.saturating_add(bytes.len());\n                    if output_bytes > max_output_bytes {\n                        bail!(\"command output exceeded {max_output_bytes} bytes\");\n                    }\n                    stderr_hasher.update(&bytes);\n                }\n                HashedProcessOutput::ReadError(stream, err) => {\n                    bail!(\"failed to read command {stream}: {err}\");\n                }\n            }\n            Ok(())\n        };\n        let mut status = None;\n        let mut wait = Box::pin(cp.wait());\n        loop {\n            tokio::select! {\n                result = &mut wait, if status.is_none() => {\n                    status = Some(result?);\n                    break;\n                }\n                output = rx.recv() => {\n                    let Some(output) = output else {\n                        status = Some(wait.await?);\n                        break;\n                    };\n                    if let Err(err) = consume(output) {","sourceCodeStart":1387,"sourceCodeEnd":1423,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/cmd.rs#L1387-L1423","documentation":"This error is thrown when an asynchronous reader task fails to read from one of the command's piped output streams (stdout or stderr) while hashing output in execute_hashes_async_with_drain_timeout. The underlying io::Error is embedded in the message along with the stream name, so the failure is a low-level pipe/OS read error rather than a command failure. The process tree is killed and the error propagated instead of returning hashes.","triggerScenarios":"The spawned reader task's stdout.read()/stderr.read() loop returns Err — e.g. the pipe descriptor becomes invalid, the OS returns EIO, or the process/pipe is torn down unexpectedly mid-read.","commonSituations":"System resource exhaustion (fd/memory pressure), a child that closes its end of the pipe in an unexpected way, or platform-specific pipe errors when many concurrent tasks run with piped output.","solutions":["Inspect the embedded io::Error in the message for the root cause (e.g. EIO, EBADF) and address that OS-level condition","Retry the command — transient pipe errors often disappear on rerun","Reduce concurrent commands to relieve fd/memory pressure","Check for resource limits (ulimit -n) and raise them if file descriptors are exhausted"],"exampleFix":"// before\n// Err: failed to read command stderr: Os { code: 9, kind: Uncategorized, message: \"Bad file descriptor\" }\n// after (raise fd limit, then retry)\nulimit -n 4096\nmise run my-task","handlingStrategy":"retry","validationCode":"// preflight: ensure fd limits are comfortable\nlet nofile = std::fs::read_to_string(\"/proc/self/limits\")?;\nif !nofile.contains(\"open files\") { /* warn */ }","typeGuard":null,"tryCatchPattern":"match cmd.execute_hashes_async(MAX).await {\n    Ok(h) => Ok(h),\n    Err(e) if e.to_string().starts_with(\"failed to read command\") => {\n        tokio::time::sleep(Duration::from_millis(500)).await;\n        cmd.execute_hashes_async(MAX).await // one retry\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Raise ulimit -n in environments running many concurrent piped commands","Avoid extreme process concurrency that stresses the kernel pipe buffers","Retry transient io errors once before surfacing","Log the embedded io::Error kind for diagnosis"],"tags":["process","io","pipe","hashing"],"backgroundTag":"broken-pipe","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}