{"record":{"id":"7434a35caeb8bf1e","repo":"can1357/oh-my-pi","slug":"underlying-bytestream-error","errorCode":null,"errorMessage":"underlying bytestream error: {}","messagePattern":"underlying bytestream error: (.+?)","errorType":"error_code","errorClass":"BufReadDecoderError","httpStatus":null,"severity":"error","filePath":"crates/pi-builtins/src/wc.rs","lineNumber":396,"sourceCode":"\t\t\n\t\t/// Wraps a `std::io::BufRead` buffered byte stream and decode it as UTF-8.\n\t\tpub struct BufReadDecoder<B: BufRead> {\n\t\t\tbuf_read:       B,\n\t\t\tbytes_consumed: usize,\n\t\t\tincomplete:     Incomplete,\n\t\t}\n\t\t\n\t\t#[derive(Debug, Error)]\n\t\tpub enum BufReadDecoderError<'a> {\n\t\t\t/// Represents one UTF-8 error in the byte stream.\n\t\t\t///\n\t\t\t/// In lossy decoding, each such error should be replaced with U+FFFD.\n\t\t\t/// (See `BufReadDecoder::next_lossy` and `BufReadDecoderError::lossy`.)\n\t\t\t#[error(\"invalid byte sequence: {:02x?}\", .0)]\n\t\t\tInvalidByteSequence(&'a [u8]),\n\t\t\n\t\t\t/// An I/O error from the underlying byte stream\n\t\t\t#[error(\"underlying bytestream error: {}\", .0)]\n\t\t\tIo(#[source] io::Error),\n\t\t}\n\t\t\n\t\timpl<B: BufRead> BufReadDecoder<B> {\n\t\t\tpub fn new(buf_read: B) -> Self {\n\t\t\t\tSelf { buf_read, bytes_consumed: 0, incomplete: Incomplete::empty() }\n\t\t\t}\n\t\t\n\t\t\t/// Decode and consume the next chunk of UTF-8 input.\n\t\t\t///\n\t\t\t/// This method is intended to be called repeatedly until it returns `None`,\n\t\t\t/// which represents EOF from the underlying byte stream.\n\t\t\t/// This is similar to `Iterator::next`,\n\t\t\t/// except that decoded chunks borrow the decoder (~iterator)\n\t\t\t/// so they need to be handled or copied before the next chunk can start\n\t\t\t/// decoding.\n\t\t\t#[allow(clippy::cognitive_complexity)]\n\t\t\tpub fn next_strict(&mut self) -> Option<Result<&str, BufReadDecoderError<'_>>> {","sourceCodeStart":378,"sourceCodeEnd":414,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/crates/pi-builtins/src/wc.rs#L378-L414","documentation":"BufReadDecoderError::Io wraps an io::Error from the underlying byte stream while the decoder was pulling more bytes. The `{}` display delegates to the inner io::Error, and the variant is marked #[source] so the root cause is preserved for error chains.","triggerScenarios":"Any read failure on the underlying BufRead during wc's incremental decoding: EACCES/EPERM mid-read, EISDIR when reading a directory, device errors, or a broken pipe on stdin.","commonSituations":"wc pointed at a directory instead of a file; permission changed while reading; reading from a failing disk or a closed pipe (`prog | wc` where prog crashed); NFS timeouts.","solutions":["Check the inner io::Error (via .source() or the printed message) for the real cause (errno)","Verify the input is a readable regular file, not a directory or unreadable path","If reading from a pipe, ensure the producer process stays alive and writes valid data","Retry transient I/O (network mounts) or copy the file locally first"],"exampleFix":"// before: wc on a directory -> Io(os error 21)\n// after\nlet path = \"target\";\nlet meta = std::fs::metadata(path)?;\nif meta.is_dir() {\n    eprintln!(\"skipping directory: {path}\");\n} else {\n    // proceed with wc on the file\n}","handlingStrategy":"retry","validationCode":"fn validate_readable(path: &std::path::Path) -> Result<(), std::io::Error> {\n    std::fs::File::open(path).map(|_| ())\n}","typeGuard":null,"tryCatchPattern":"match result {\n    Err(BufReadDecoderError::Io(e)) if e.kind() == std::io::ErrorKind::PermissionDenied => {\n        eprintln!(\"permission denied; skipping\");\n    }\n    Err(BufReadDecoderError::Io(e)) if e.raw_os_error() == Some(21) => {\n        eprintln!(\"input is a directory; skipping\");\n    }\n    Err(BufReadDecoderError::Io(e)) => {\n        // transient (EIO/ETIMEDOUT): retry after backoff\n    }\n    other => other.map(|_| ()),\n}","preventionTips":["Verify inputs are readable regular files before processing","Copy network-mounted files locally before heavy reading","Keep pipe producers alive until consumers finish","Check ErrorKind on the wrapped io::Error for branching logic"],"tags":["io","wc","stream","read-error"],"backgroundTag":"io-read-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}