uutils/coreutils · error · io::Error
od-error-skip-past-end
Error message
od-error-skip-past-end
What it means
od's MultifileReader::skip advances past n_skip bytes across the sequence of input files, advancing to the next file whenever the current one is exhausted. If, after consuming all input files, bytes remain to skip (n_skip > 0), the input is shorter than the requested skip amount and it returns an UnexpectedEof io::Error carrying this localized message. od throws it because byte offsets past the end of all inputs are undefined for output positioning.
Source
Thrown at src/uu/od/src/multifile_reader.rs:156
/// special file (e.g. `/dev/null`, which can be skipped past its empty end).
/// Everything else - proc/sys files that report a bogus size, pipes, stdin -
/// is advanced by reading and discarding. Skipping past the end of the whole
/// input is an error, matching GNU `od`.
pub fn skip(&mut self, mut n_skip: u64) -> io::Result<()> {
while n_skip > 0 {
let Some(curr) = self.curr_file.as_mut() else {
break;
};
n_skip = skip_in_file(curr, n_skip)?;
if n_skip == 0 {
break;
}
// Current file is exhausted; continue skipping in the next one.
self.next_file();
}
if n_skip > 0 {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
translate!("od-error-skip-past-end"),
));
}
Ok(())
}
}
/// Skip up to `n_skip` bytes within a single file. Returns the number of bytes
/// that still need to be skipped (0 if the skip landed inside this file, or
/// the remainder if the file ended first).
fn skip_in_file(curr: &mut CurrentReader, n_skip: u64) -> io::Result<u64> {
#[cfg(unix)]
if let CurrentReader::File(f) = curr
&& let Ok(meta) = f.metadata()
{
let size = meta.len();
let blksize = uucore::fs::sane_blksize::sane_blksize_from_metadata(&meta);View on GitHub (pinned to 325183372a)
Solutions
- Reduce the --skip-bytes value to at most the total input size (`stat -c %s file1 file2 | paste -sd+ | bc`).
- Verify the input files are complete (re-download/re-copy truncated files) and check their sizes.
- Check the skip unit — GNU od accepts suffixes like b (blocks of 512); a wrong unit can overshoot the file.
- If skipping in a pipeline, ensure upstream producers actually wrote enough bytes before od reads.
Example fix
// before od --skip-bytes=100000 small.txt // file is only 4 KB // after size=$(stat -c %s small.txt); od --skip-bytes=$((size > 100000 ? 100000 : size - 1)) small.txt
Defensive patterns
Strategy: validation
Validate before calling
let total: u64 = std::fs::metadata("input.txt")?.len();
let skip: u64 = 100000;
if skip > total {
eprintln!("skip {skip} exceeds input size {total}");
// clamp or load a larger input
} Type guard
fn skip_fits(skip: u64, inputs: &[&str]) -> std::io::Result<bool> {
let total: u64 = inputs.iter().try_fold(0u64, |acc, f| Ok(acc + std::fs::metadata(f)?.len()))?;
Ok(skip <= total)
} Try / catch
match od_result {
Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => {
// skip past end: clamp skip to total input size and retry
}
r => r?,
} Prevention
- Compute skip offsets from actual file sizes (stat), never hardcode
- Watch od skip unit suffixes (b = 512-byte blocks) to avoid overshooting
- Verify input file completeness (sizes/checksums) before offset-based reads
When it happens
Trigger: Running `od` with `--skip-bytes=N` (or equivalent skip option) where N exceeds the total size of all input files combined; also via open_input_peek_reader which calls skip during reader setup.
Common situations: Script computing skip offsets from a larger file but reading a truncated/rotated one; off-by-one or wrong unit (chars vs bytes) in skip arguments; piping/copying partial logs; combining multiple small files while assuming a larger total.
AI-assisted analysis of uutils/coreutils@325183372a (2026-08-31).
Data as JSON: /api/errors/560dc1343a398410.
Report an issue: GitHub.