can1357/oh-my-pi · error · BufReadDecoderError
underlying bytestream error: {}
Error message
underlying bytestream error: {} What it means
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.
Source
Thrown at crates/pi-builtins/src/wc.rs:396
/// Wraps a `std::io::BufRead` buffered byte stream and decode it as UTF-8.
pub struct BufReadDecoder<B: BufRead> {
buf_read: B,
bytes_consumed: usize,
incomplete: Incomplete,
}
#[derive(Debug, Error)]
pub enum BufReadDecoderError<'a> {
/// Represents one UTF-8 error in the byte stream.
///
/// In lossy decoding, each such error should be replaced with U+FFFD.
/// (See `BufReadDecoder::next_lossy` and `BufReadDecoderError::lossy`.)
#[error("invalid byte sequence: {:02x?}", .0)]
InvalidByteSequence(&'a [u8]),
/// An I/O error from the underlying byte stream
#[error("underlying bytestream error: {}", .0)]
Io(#[source] io::Error),
}
impl<B: BufRead> BufReadDecoder<B> {
pub fn new(buf_read: B) -> Self {
Self { buf_read, bytes_consumed: 0, incomplete: Incomplete::empty() }
}
/// Decode and consume the next chunk of UTF-8 input.
///
/// This method is intended to be called repeatedly until it returns `None`,
/// which represents EOF from the underlying byte stream.
/// This is similar to `Iterator::next`,
/// except that decoded chunks borrow the decoder (~iterator)
/// so they need to be handled or copied before the next chunk can start
/// decoding.
#[allow(clippy::cognitive_complexity)]
pub fn next_strict(&mut self) -> Option<Result<&str, BufReadDecoderError<'_>>> {View on GitHub (pinned to 9690622007)
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
Example fix
// before: wc on a directory -> Io(os error 21)
// after
let path = "target";
let meta = std::fs::metadata(path)?;
if meta.is_dir() {
eprintln!("skipping directory: {path}");
} else {
// proceed with wc on the file
} Defensive patterns
Strategy: retry
Validate before calling
fn validate_readable(path: &std::path::Path) -> Result<(), std::io::Error> {
std::fs::File::open(path).map(|_| ())
} Try / catch
match result {
Err(BufReadDecoderError::Io(e)) if e.kind() == std::io::ErrorKind::PermissionDenied => {
eprintln!("permission denied; skipping");
}
Err(BufReadDecoderError::Io(e)) if e.raw_os_error() == Some(21) => {
eprintln!("input is a directory; skipping");
}
Err(BufReadDecoderError::Io(e)) => {
// transient (EIO/ETIMEDOUT): retry after backoff
}
other => other.map(|_| ()),
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- {}: read error: {}
- {context}: {source}
- Failed to read tar archive
- Computed edit range is out of bounds
- I/O error occurred
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/7434a35caeb8bf1e.
Report an issue: GitHub.