{"record":{"id":"e9c8b630b677620a","repo":"tursodatabase/turso","slug":"unexpectedeof","errorCode":"UnexpectedEof","errorMessage":"range exceeds file length","messagePattern":"range exceeds file length","errorType":"exception","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"core/index_method/fts.rs","lineNumber":854,"sourceCode":"\nimpl std::fmt::Debug for InMemoryFileHandle {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"InMemoryFileHandle\")\n            .field(\"len\", &self.data.len())\n            .finish()\n    }\n}\n\nimpl HasLen for InMemoryFileHandle {\n    fn len(&self) -> usize {\n        self.data.len()\n    }\n}\n\nimpl FileHandle for InMemoryFileHandle {\n    fn read_bytes(&self, range: Range<usize>) -> std::io::Result<OwnedBytes> {\n        if range.end > self.data.len() {\n            return Err(std::io::Error::new(\n                std::io::ErrorKind::UnexpectedEof,\n                \"range exceeds file length\",\n            ));\n        }\n        if range.start >= range.end {\n            return Ok(OwnedBytes::empty());\n        }\n        Ok(OwnedBytes::new(Arc::clone(&self.data)).slice(range))\n    }\n}\n\n/// In-memory writer for HybridBTreeDirectory.\nstruct HybridWriter {\n    path: PathBuf,\n    buffer: Vec<u8>,\n    directory: HybridBTreeDirectory,\n}\n","sourceCodeStart":836,"sourceCodeEnd":872,"githubUrl":"https://github.com/tursodatabase/turso/blob/0e69fa4af1a4ff174ecb61d19f728df0ab41c218/core/index_method/fts.rs#L836-L872","documentation":"The in-memory FileHandle used by the FTS token collector serves read_bytes(range) from a byte buffer; a range whose end exceeds the buffer length returns UnexpectedEof \"range exceeds file length\". It guards against offset metadata claiming data that was never written.","triggerScenarios":"Index offset/size metadata inconsistent with the in-memory data - a truncated write buffer after an interrupt, a collector reused after its data was replaced, or a computed read range beyond what was flushed.","commonSituations":"Crash or interrupt during an index build leaving short data, or an FTS index produced by a mismatched turso version.","solutions":["Rebuild the FTS index so metadata and data are regenerated consistently","If it recurs on rebuild, capture the query and index DDL and report it as a turso bug","Restore from backup for production data"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"match handle.read_bytes(range.clone()) {\n    Err(ref e) if e.kind() == std::io::ErrorKind::UnexpectedEof => rebuild_index(),\n    r => r,\n}","preventionTips":["Rebuild FTS indexes after upgrading turso","Avoid interrupting long index builds","Validate index state after restores"],"tags":["fts","full-text-search","eof","index","rust"],"backgroundTag":"unexpected-eof","analyzedSha":"0e69fa4af1a4ff174ecb61d19f728df0ab41c218","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}