can1357/oh-my-pi · error · TacError
failed to write to stdout: {}
Error message
failed to write to stdout: {} What it means
This tac builtin error (crates/pi-builtins/src/tac.rs, Write) means writing the reversed output to stdout failed. It carries an errno-stripped io::Error (e.g. EPIPE when the downstream reader closed the pipe). This is an output-side failure, not an input problem.
Source
Thrown at crates/pi-builtins/src/tac.rs:39
pub static BEFORE: &str = "before";
pub static REGEX: &str = "regex";
pub static SEPARATOR: &str = "separator";
pub static FILE: &str = "file";
}
#[derive(Debug, Error)]
enum TacError {
/// A regular expression given by the user is invalid.
#[error("invalid regular expression: {0}")]
InvalidRegex(regex::Error),
/// An error opening a file for reading.
#[error("failed to open {} for reading: {}", .0.quote(), strip_errno(.1))]
Open(OsString, std::io::Error),
/// An error reading the contents of a file or stdin.
#[error("{}: read error: {}", .0.maybe_quote(), strip_errno(.1))]
Read(OsString, std::io::Error),
/// An error writing the reversed contents of a file or stdin.
#[error("failed to write to stdout: {}", strip_errno(.0))]
Write(std::io::Error),
}
fn strip_errno(error: &std::io::Error) -> String {
let mut message = error.to_string();
if let Some(position) = message.find(" (os error ") {
message.truncate(position);
}
message
}
/// Parsed `tac` invocation.
pub(crate) struct Tac {
matches: ArgMatches,
}
matches_parser!(Tac, app);
View on GitHub (pinned to 9690622007)
Solutions
- If truncation was intended (e.g. piping to head), ignore the broken-pipe condition; it is expected behavior.
- Check free space on the filesystem receiving the output (`df -h`) when redirecting to a file.
- Ensure stdout is open in the calling context (avoid running with >&-).
- Handle SIGPIPE/BrokenPipe in wrapping scripts so partial output is treated as success.
Example fix
// before: noisy EPIPE tac huge.log | head -n 10 // failed to write to stdout: Broken pipe // after: suppress expected broken pipe tac huge.log | head -n 10 2>/dev/null || true
Defensive patterns
Strategy: try-catch
Type guard
function isWriteError(err) {
return err instanceof Error && err.message.startsWith('failed to write to stdout: ');
} Try / catch
try {
await tac.run([file]);
} catch (err) {
const msg = String(err);
if (msg.startsWith('failed to write to stdout:') && /broken pipe|os error 32/i.test(msg)) {
// downstream closed early (e.g. head): treat as success
return;
} else throw err;
} Prevention
- Treat EPIPE from piping into head/less as expected and suppress it.
- Check free disk space before redirecting large output.
- Do not close or detach stdout of processes whose output you need.
When it happens
Trigger: Downstream consumer exits early: `tac big.txt | head -5` (SIGPIPE/EPIPE); stdout redirected to a full disk or a closed descriptor; output quota exceeded.
Common situations: Piping into head/less/grep that stops reading; shell jobs killed; /tmp or the redirect target filesystem full; detached processes with closed stdout.
Related errors
- error writing 'standard output': {err}
- Computed edit range is out of bounds
- failed to open {} for reading: {}
- {}: read error: {}
- Replacement text is not valid UTF-8: {err}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/265adeece1be55a8.
Report an issue: GitHub.