quickwit-oss/tantivy · error · io::Error
InvalidInput
InvalidInput
Error message
Invalid range
What it means
A FileSlice read implementation computes the clamped read window (end clamped to file length) and rejects any request where start >= end with InvalidInput 'Invalid range'. This catches empty ranges and ranges starting at or beyond EOF rather than silently returning zero bytes.
Source
Thrown at common/src/file_slice.rs:62
/// Creates a new WrapFile and stores its length.
pub fn new(file: File) -> io::Result<Self> {
let len = file.metadata()?.len() as usize;
Ok(WrapFile { file, len })
}
}
#[async_trait]
impl FileHandle for WrapFile {
fn read_bytes(&self, range: Range<usize>) -> io::Result<OwnedBytes> {
let file_len = self.len();
// Calculate the actual range to read, ensuring it stays within file boundaries
let start = range.start;
let end = range.end.min(file_len);
// Ensure the start is before the end of the range
if start >= end {
return Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid range"));
}
let mut buffer = vec![0; end - start];
#[cfg(unix)]
{
use std::os::unix::prelude::FileExt;
self.file.read_exact_at(&mut buffer, start as u64)?;
}
#[cfg(not(unix))]
{
use std::io::{Read, Seek};
let mut file = self.file.try_clone()?; // Clone the file to read from it separately
// Seek to the start position in the file
file.seek(io::SeekFrom::Start(start as u64))?;
// Read the data into the buffer
file.read_exact(&mut buffer)?;View on GitHub (pinned to b5d8deb80c)
Solutions
- Clamp range.start to < file_len and ensure start < end before calling read_bytes
- Skip reads with empty ranges instead of issuing them (treat as empty result)
- Verify the file wasn't truncated (compare actual length to expected header/footer sizes)
- Fix offset arithmetic that yields start == end or start beyond EOF
Example fix
// before
let bytes = slice.read_bytes(off..off + len)?; // len == 0 possible
// after
let bytes = if off < file_len && len > 0 { slice.read_bytes(off..(off + len).min(file_len))? } else { OwnedBytes::empty() }; Defensive patterns
Strategy: validation
Validate before calling
fn safe_range(range: Range<usize>, file_len: usize) -> Option<Range<usize>> {
let end = range.end.min(file_len);
(range.start < end).then(|| range.start..end)
}
// guard: if let Some(r) = safe_range(off..off+len, file_len) { slice.read_bytes(r)?; } Try / catch
match slice.read_bytes(range.clone()) {
Err(e) if e.kind() == io::ErrorKind::InvalidInput && e.to_string() == "Invalid range" =>
Ok(OwnedBytes::empty()), // or fix offsets and retry
other => other,
} Prevention
- Clamp ranges against the actual file length before reading
- Treat empty ranges as no-ops instead of issuing reads
- Recompute offsets from the current file, not stale metadata
- Detect truncated files by comparing stored vs actual lengths
When it happens
Trigger: Calling read_bytes with a zero-length range (start == end), a range entirely past the file end (start > file_len), or a start beyond the clamped end on a file smaller than requested.
Common situations: Computing footer/metadata offsets from a stale or wrong file length; off-by-one in end offsets (start == end); reading from a truncated file where stored offsets exceed actual size.
Related errors
- Unsupported
- Internal Error: Called get_val of empty column.
- Corrupted data. Invalid VInt 32
- InvalidData
- UnexpectedEof
AI-assisted analysis of quickwit-oss/tantivy@b5d8deb80c (2026-09-05).
Data as JSON: /api/errors/5cf42d2f13dbe5b6.
Report an issue: GitHub.