tursodatabase/turso · critical
invalid MVCC logical log magic
Error message
invalid MVCC logical log magic
What it means
validate_mvcc_log_header checked the first 4 bytes of the .db-log file against MVCC_LOG_MAGIC and they do not match. The file at the logical-log path is simply not an MVCC logical log: a wrong or foreign file, garbage content, or a log written by an incompatible format/tool.
Solutions
- Confirm the .db-log file was produced by this server build for this exact database
- Remove the invalid log and let the server regenerate it, forcing clients to re-bootstrap
- Restore the db and .db-log pair from a consistent backup
Defensive patterns
Strategy: fallback
Validate before calling
// pre-flight magic check before serving logical pulls
let mut head = [0u8; 4];
std::fs::File::open(&log_path)?.read_exact(&mut head)?;
if head != MVCC_LOG_MAGIC.to_le_bytes() {
return Err(anyhow!("file at {} is not an MVCC logical log", log_path.display()));
} Try / catch
match scan_mvcc_log(&log_bytes) {
Ok(snapshot) => snapshot,
Err(e) if e.to_string() == "invalid MVCC logical log magic" => {
// wrong file at the .db-log path: remove, regenerate, and re-bootstrap clients
std::fs::remove_file(&log_path)?;
regenerate_logical_log()?;
scan_mvcc_log(&std::fs::read(&log_path)?)?
}
Err(e) => return Err(e),
} Prevention
- Give each database a unique path so .db-log names cannot collide
- After server upgrades, regenerate or verify the logical log instead of reusing old files
- Restore db and .db-log together from a consistent backup
When it happens
Trigger: A stale or unrelated file occupies <db>.db-log (rename/copy mistake); the log format changed between builds; the first bytes were corrupted (bit rot, partial overwrite); any logical pull then fails header validation.
Common situations: Reusing paths across server versions; accidentally pointing two databases at colliding .db-log names; files mangled by tooling or editors.
Related errors
- invalid MVCC logical log frame end magic at offset
- invalid MVCC logical log frame magic at offset
- truncated MVCC logical log header: len=
- unsupported MVCC logical log version
- buffer too short for u32 at offset
AI-assisted analysis of tursodatabase/turso@492c4a71cd (2026-08-20).
Data as JSON: /api/errors/96f42920d8ab5471.
Report an issue: GitHub.
Appendix: source
Thrown at cli/sync_server.rs:1100
running_crc = frame_crc;
offset = frame_end;
crc_by_offset.push((offset as u64, running_crc));
}
Ok(MvccLogSnapshot {
end_offset: offset as u64,
crc_by_offset,
})
}
fn is_nonportable_mvcc_log_error(err: &anyhow::Error) -> bool {
let message = err.to_string();
message.starts_with("unsupported MVCC logical log version ")
}
fn validate_mvcc_log_header(log: &[u8]) -> Result<()> {
if read_u32_le(log, 0)? != MVCC_LOG_MAGIC {
return Err(anyhow!("invalid MVCC logical log magic"));
}
if log[4] != MVCC_LOG_VERSION {
return Err(anyhow!("unsupported MVCC logical log version {}", log[4]));
}
if log[5] & 0b1111_1110 != 0 {
return Err(anyhow!("invalid MVCC logical log header flags"));
}
let header_len = u16::from_le_bytes([log[6], log[7]]) as usize;
if header_len != MVCC_LOG_HEADER_SIZE {
return Err(anyhow!(
"invalid MVCC logical log header length: {header_len}"
));
}
if log[MVCC_LOG_HEADER_RESERVED_START..MVCC_LOG_HEADER_CRC_START]
.iter()
.any(|byte| *byte != 0)
{
return Err(anyhow!(View on GitHub (pinned to 492c4a71cd)