tursodatabase/turso · error · anyhow::Error
invalid MVCC logical log frame end magic at offset
Error message
invalid MVCC logical log frame end magic at offset {offset} What it means
Each frame trailer ends with MVCC_TX_END_MAGIC at trailer_start+4. The frame CRC only covers bytes before the trailer, so a corrupted end-magic word can pass the CRC check and fail here. It also fires when a wrong payload size shifts trailer_start into the middle of the payload (usually caught earlier by the CRC, making this a rare, narrow corruption signature).
Solutions
- Restore the log from backup or regenerate it
- If it recurs, capture the offending frame bytes and check for storage-level corruption
Defensive patterns
Strategy: try-catch
Try / catch
let snapshot = match scan_mvcc_log(&log) {
Ok(s) => s,
Err(err) if err.to_string().contains("frame end magic") => {
// trailer magic corrupt (CRC passed, so damage is localized)
restore_or_rebuild()?
}
Err(err) => return Err(err),
}; Prevention
- Preserve the end-magic check when modifying the frame format
- Treat repeated trailer-only corruption as a storage-hardware symptom
- Keep backups so any single-frame corruption is a restore, not an investigation
When it happens
Trigger: read_mvcc_frame_boundary reads the u32 at trailer_start+4 and finds anything other than MVCC_TX_END_MAGIC after the frame CRC already matched.
Common situations: A bit flip localized to the trailer's magic word; truncated-then-refilled files; layout desync from an earlier size-field corruption.
Related errors
- invalid MVCC logical log frame magic at offset
- invalid MVCC logical log header flags
- invalid MVCC logical log header length
- invalid MVCC logical log magic
- MVCC logical log extension block missing flag at offset
AI-assisted analysis of tursodatabase/turso@492c4a71cd (2026-08-20).
Data as JSON: /api/errors/28cf88971cd0caf9.
Report an issue: GitHub.
Appendix: source
Thrown at cli/sync_server.rs:1211
.and_then(|value| value.checked_add(payload_size))
.and_then(|value| value.checked_add(extension_size))
.ok_or_else(|| anyhow!("MVCC logical log frame offset overflow"))?;
let frame_end = trailer_start
.checked_add(MVCC_TX_TRAILER_SIZE)
.ok_or_else(|| anyhow!("MVCC logical log frame end overflow"))?;
if frame_end > log.len() {
return Ok(None);
}
let expected_crc = crc32c::crc32c_append(running_crc, &log[offset..trailer_start]);
let stored_crc = read_u32_le(log, trailer_start)?;
if stored_crc != expected_crc {
return Err(anyhow!(
"MVCC logical log frame checksum mismatch at offset {offset}"
));
}
let end_magic = read_u32_le(log, trailer_start + 4)?;
if end_magic != MVCC_TX_END_MAGIC {
return Err(anyhow!(
"invalid MVCC logical log frame end magic at offset {offset}"
));
}
Ok(Some((frame_end, stored_crc)))
}
fn read_u32_le(buf: &[u8], offset: usize) -> Result<u32> {
let bytes = buf
.get(offset..offset + 4)
.ok_or_else(|| anyhow!("buffer too short for u32 at offset {offset}"))?;
Ok(u32::from_le_bytes(bytes.try_into().unwrap()))
}
fn read_u64_le(buf: &[u8], offset: usize) -> Result<u64> {
let bytes = buf
.get(offset..offset + 8)
.ok_or_else(|| anyhow!("buffer too short for u64 at offset {offset}"))?;
Ok(u64::from_le_bytes(bytes.try_into().unwrap()))View on GitHub (pinned to 492c4a71cd)