spacejam/sled · error
corrupt frame length
Error message
corrupt frame length
What it means
read_frame reads an 8-byte frame length with its own checksum; the two high bytes are masked out before conversion to u64, and the stored length hash must match the recomputed hash. A mismatch means the length header is corrupt, so the frame cannot be trusted or sized, and the read fails.
Solutions
- Restore the metadata files from backup or delete them to force a rebuild if the data is recoverable elsewhere
- Check for preceding corruption that desynchronized frame alignment and rescan from a known-good offset
- Run disk/filesystem health checks and replace failing storage
- If data is expendable, recreate the database
Defensive patterns
Strategy: try-catch
Validate before calling
// validate metadata log files exist and are non-empty before opening
for f in ["blob", "logs"] { let p = path.join(f); if !p.exists() { return Err(anyhow!("missing metadata: {}", f)); } } Try / catch
match Db::open(&path) {
Ok(db) => db,
Err(e) if e.to_string().contains("corrupt frame length") => {
// truncate/restore corrupt metadata segment, then retry
repair_or_restore_metadata(&path)?;
Db::open(&path)?
}
Err(e) => return Err(e.into()),
} Prevention
- Back up the metadata store regularly
- Ensure clean shutdowns so frames are fully written
- Monitor storage health; frame-length corruption usually means bit rot or torn writes
- Avoid moving db files between systems without checksum verification
When it happens
Trigger: Reading a metadata log/snapshot frame whose length bytes were corrupted by torn writes, power loss, bit rot, or a misaligned read offset (e.g. after a previously corrupted frame desynchronized the log).
Common situations: Crash recovery replaying the metadata log; damaged snapshot files; failing disk sectors in the metadata region.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- crc mismatch for read of batch frame
- encountered corrupted settings cookie with mismatched CRC.
- crc mismatch - data corruption detected
- corrupt object ID 0 somehow passed crc check
- Db's LEAF_FANOUT const generic must be 3 or greater.
AI-assisted analysis of spacejam/sled@e449d17111 (2026-09-12).
Data as JSON: /api/errors/acbc668844dab7e2.
Report an issue: GitHub.
Appendix: source
Thrown at src/metadata_store.rs:517
reusable_frame_buffer: &mut Vec<u8>,
) -> io::Result<Vec<UpdateMetadata>> {
let mut frame_size_with_crc_buf: [u8; 8] = [0; 8];
// TODO only break if UnexpectedEof, otherwise propagate
fallible!(file.read_exact(&mut frame_size_with_crc_buf));
let expected_len_hash_buf =
[frame_size_with_crc_buf[6], frame_size_with_crc_buf[7]];
let actual_len_hash_buf: [u8; 2] =
(crc32fast::hash(&frame_size_with_crc_buf[..6]) as u16).to_le_bytes();
// clear crc bytes before turning into usize
let mut frame_size_buf = frame_size_with_crc_buf;
frame_size_buf[6] = 0;
frame_size_buf[7] = 0;
if actual_len_hash_buf != expected_len_hash_buf {
return Err(annotate!(io::Error::new(
io::ErrorKind::InvalidData,
"corrupt frame length"
)));
}
let len_u64: u64 = u64::from_le_bytes(frame_size_buf);
let len: usize = usize::try_from(len_u64).unwrap();
reusable_frame_buffer.clear();
reusable_frame_buffer.reserve(len + 12);
unsafe {
reusable_frame_buffer.set_len(len + 12);
}
reusable_frame_buffer[..8].copy_from_slice(&frame_size_with_crc_buf);
fallible!(file.read_exact(&mut reusable_frame_buffer[8..]));
let crc_actual = crc32fast::hash(&reusable_frame_buffer[..len + 8]) ^ 0xAF;View on GitHub (pinned to e449d17111)