{"record":{"id":"bd39cb2ff72e9448","repo":"quickwit-oss/tantivy","slug":"failed-to-read-block-len","errorCode":null,"errorMessage":"failed to read block_len","messagePattern":"failed to read block_len","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"sstable/src/block_reader.rs","lineNumber":88,"sourceCode":"        self.buffer.clear();\n\n        loop {\n            let block_len = match self.reader.len() {\n                0 => {\n                    // we are out of data for this block. Check if we have another block after\n                    match self.next_readers.next() {\n                        Some((new_reader, first_ordinal)) => {\n                            self.reader = new_reader;\n                            self.pending_first_ordinal = Some(first_ordinal);\n                            continue;\n                        }\n                        _ => {\n                            return Ok(false);\n                        }\n                    }\n                }\n                1..=3 => {\n                    return Err(io::Error::new(\n                        io::ErrorKind::UnexpectedEof,\n                        \"failed to read block_len\",\n                    ));\n                }\n                _ => self.reader.read_u32() as usize,\n            };\n            if block_len <= 1 {\n                return Ok(false);\n            }\n            let compress = self.reader.read_u8();\n            let block_len = block_len - 1;\n\n            if self.reader.len() < block_len {\n                return Err(io::Error::new(\n                    io::ErrorKind::UnexpectedEof,\n                    \"failed to read block content\",\n                ));\n            }","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/quickwit-oss/tantivy/blob/b5d8deb80c26924e6b007a5b1a7630f35ca64de4/sstable/src/block_reader.rs#L70-L106","documentation":"Thrown by the SSTable block reader's read_block() when the encoded block_len field is 1..=3 bytes. A legal block length prefix is either 0 (special/last marker) or 4 bytes; a 1-3 byte length is structurally impossible, so the reader reports UnexpectedEof — the stream is misaligned or truncated.","triggerScenarios":"Reading an SSTable stream where the next block_len byte count lands on 1..=3; this occurs with truncated files or when the read offset drifts into the middle of a length prefix due to prior misparses.","commonSituations":"Corrupted or truncated SSTable files; reading an SSTable written by an incompatible format version; incorrect seek/offset handling by the caller leading to mid-token reads.","solutions":["Verify the SSTable file is complete and uncorrupted (compare size/checksum with the source)","Rebuild the index or restore the SSTable from backup","Ensure the reader starts at a valid block boundary offset (e.g. from the index/dictionary) rather than an arbitrary position","Check writer/reader format version compatibility"],"exampleFix":"// before\nmatch self.reader.read_bytes(1)? {\n    0 => /* ... */,\n    1..=3 => return Err(io::Error::new(io::ErrorKind::UnexpectedEof, \"failed to read block_len\")),\n    _ => self.reader.read_u32() as usize,\n}\n// after\nmatch self.reader.read_bytes(1)? {\n    0 => /* ... */,\n    1..=3 => return Err(io::Error::new(io::ErrorKind::UnexpectedEof, format!(\"failed to read block_len: invalid length prefix at offset {}\", self.reader.pos()))),\n    _ => self.reader.read_u32() as usize,\n}","handlingStrategy":"validation","validationCode":"fn sstable_offset_is_block_aligned(reader: &BlockReader, offset: usize) -> bool {\n    // a valid block starts with a length prefix of 0 or 4\n    if offset >= reader.len() { return false; }\n    match reader.peek_u8_at(offset) {\n        Some(0) | Some(4) => true,\n        _ => false,\n    }\n}","typeGuard":"fn has_valid_block_len_prefix(byte: u8) -> bool {\n    byte == 0 || byte == 4\n}","tryCatchPattern":"match block_reader.read_block() {\n    Err(e) if e.kind() == io::ErrorKind::UnexpectedEof\n        && e.to_string() == \"failed to read block_len\" => {\n        eprintln!(\"SSTable truncated or offset misaligned; restoring from backup\");\n    }\n    Err(e) => return Err(e.into()),\n    Ok(done) => if !done { /* process block */ },\n}","preventionTips":["Only seek to block offsets obtained from the SSTable index, never arbitrary positions","Verify file completeness after copies; truncated files fail at the first bad prefix","Use matching SSTable format versions for writer and reader","Detect truncation early by validating total file size against expected metadata"],"tags":["io","sstable","truncation","rust"],"backgroundTag":"truncated-block","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"}