{"record":{"id":"265adeece1be55a8","repo":"can1357/oh-my-pi","slug":"failed-to-write-to-stdout","errorCode":null,"errorMessage":"failed to write to stdout: {}","messagePattern":"failed to write to stdout: (.+?)","errorType":"error_code","errorClass":"TacError","httpStatus":null,"severity":"error","filePath":"crates/pi-builtins/src/tac.rs","lineNumber":39,"sourceCode":"\tpub static BEFORE: &str = \"before\";\n\tpub static REGEX: &str = \"regex\";\n\tpub static SEPARATOR: &str = \"separator\";\n\tpub static FILE: &str = \"file\";\n}\n\n#[derive(Debug, Error)]\nenum TacError {\n\t/// A regular expression given by the user is invalid.\n\t#[error(\"invalid regular expression: {0}\")]\n\tInvalidRegex(regex::Error),\n\t/// An error opening a file for reading.\n\t#[error(\"failed to open {} for reading: {}\", .0.quote(), strip_errno(.1))]\n\tOpen(OsString, std::io::Error),\n\t/// An error reading the contents of a file or stdin.\n\t#[error(\"{}: read error: {}\", .0.maybe_quote(), strip_errno(.1))]\n\tRead(OsString, std::io::Error),\n\t/// An error writing the reversed contents of a file or stdin.\n\t#[error(\"failed to write to stdout: {}\", strip_errno(.0))]\n\tWrite(std::io::Error),\n}\n\nfn strip_errno(error: &std::io::Error) -> String {\n\tlet mut message = error.to_string();\n\tif let Some(position) = message.find(\" (os error \") {\n\t\tmessage.truncate(position);\n\t}\n\tmessage\n}\n\n/// Parsed `tac` invocation.\npub(crate) struct Tac {\n\tmatches: ArgMatches,\n}\n\nmatches_parser!(Tac, app);\n","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/crates/pi-builtins/src/tac.rs#L21-L57","documentation":"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.","triggerScenarios":"Downstream consumer exits early: `tac big.txt | head -5` (SIGPIPE/EPIPE); stdout redirected to a full disk or a closed descriptor; output quota exceeded.","commonSituations":"Piping into head/less/grep that stops reading; shell jobs killed; /tmp or the redirect target filesystem full; detached processes with closed stdout.","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."],"exampleFix":"// before: noisy EPIPE\ntac huge.log | head -n 10  // failed to write to stdout: Broken pipe\n\n// after: suppress expected broken pipe\ntac huge.log | head -n 10 2>/dev/null || true","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isWriteError(err) {\n  return err instanceof Error && err.message.startsWith('failed to write to stdout: ');\n}","tryCatchPattern":"try {\n  await tac.run([file]);\n} catch (err) {\n  const msg = String(err);\n  if (msg.startsWith('failed to write to stdout:') && /broken pipe|os error 32/i.test(msg)) {\n    // downstream closed early (e.g. head): treat as success\n    return;\n  } else throw err;\n}","preventionTips":["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."],"tags":["io","tac","stdout","broken-pipe"],"backgroundTag":"broken-pipe","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}