{"record":{"id":"5cf42d2f13dbe5b6","repo":"quickwit-oss/tantivy","slug":"invalidinput-5cf42d","errorCode":"InvalidInput","errorMessage":"Invalid range","messagePattern":"Invalid range","errorType":"error_code","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"common/src/file_slice.rs","lineNumber":62,"sourceCode":"    /// Creates a new WrapFile and stores its length.\n    pub fn new(file: File) -> io::Result<Self> {\n        let len = file.metadata()?.len() as usize;\n        Ok(WrapFile { file, len })\n    }\n}\n\n#[async_trait]\nimpl FileHandle for WrapFile {\n    fn read_bytes(&self, range: Range<usize>) -> io::Result<OwnedBytes> {\n        let file_len = self.len();\n\n        // Calculate the actual range to read, ensuring it stays within file boundaries\n        let start = range.start;\n        let end = range.end.min(file_len);\n\n        // Ensure the start is before the end of the range\n        if start >= end {\n            return Err(io::Error::new(io::ErrorKind::InvalidInput, \"Invalid range\"));\n        }\n\n        let mut buffer = vec![0; end - start];\n\n        #[cfg(unix)]\n        {\n            use std::os::unix::prelude::FileExt;\n            self.file.read_exact_at(&mut buffer, start as u64)?;\n        }\n\n        #[cfg(not(unix))]\n        {\n            use std::io::{Read, Seek};\n            let mut file = self.file.try_clone()?; // Clone the file to read from it separately\n            // Seek to the start position in the file\n            file.seek(io::SeekFrom::Start(start as u64))?;\n            // Read the data into the buffer\n            file.read_exact(&mut buffer)?;","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/quickwit-oss/tantivy/blob/b5d8deb80c26924e6b007a5b1a7630f35ca64de4/common/src/file_slice.rs#L44-L80","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nlet bytes = slice.read_bytes(off..off + len)?; // len == 0 possible\n// after\nlet bytes = if off < file_len && len > 0 { slice.read_bytes(off..(off + len).min(file_len))? } else { OwnedBytes::empty() };","handlingStrategy":"validation","validationCode":"fn safe_range(range: Range<usize>, file_len: usize) -> Option<Range<usize>> {\n    let end = range.end.min(file_len);\n    (range.start < end).then(|| range.start..end)\n}\n// guard: if let Some(r) = safe_range(off..off+len, file_len) { slice.read_bytes(r)?; }","typeGuard":null,"tryCatchPattern":"match slice.read_bytes(range.clone()) {\n    Err(e) if e.kind() == io::ErrorKind::InvalidInput && e.to_string() == \"Invalid range\" =>\n        Ok(OwnedBytes::empty()), // or fix offsets and retry\n    other => other,\n}","preventionTips":["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"],"tags":["io","range","bounds","file-slice"],"backgroundTag":"invalid-read-range","analyzedSha":"b5d8deb80c26924e6b007a5b1a7630f35ca64de4","analyzedAt":"2026-09-05T13:20:51.521Z","contentChangedAt":"2026-09-05T13:20:51.521Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}