tursodatabase/turso · error
MVCC logical log header reserved bytes must be zero
Error message
MVCC logical log header reserved bytes must be zero
What it means
Header bytes 16 through 51 (MVCC_LOG_HEADER_RESERVED_START..MVCC_LOG_HEADER_CRC_START) are reserved and must be all zero. The validator rejects any log that sets them because this build assigns no meaning to those bytes and cannot interpret a header that uses them. Together with the checksum check that follows, it catches both tampering and logs from divergent builds that store data in reserved space.
Source
Thrown at cli/sync_server.rs:1003
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!(
"MVCC logical log header reserved bytes must be zero"
));
}
let stored_crc = read_u32_le(log, MVCC_LOG_HEADER_CRC_START)?;
let mut crc_buf = [0u8; MVCC_LOG_HEADER_SIZE];
crc_buf.copy_from_slice(&log[..MVCC_LOG_HEADER_SIZE]);
crc_buf[MVCC_LOG_HEADER_CRC_START..MVCC_LOG_HEADER_SIZE].fill(0);
let expected_crc = crc32c::crc32c(&crc_buf);
if stored_crc != expected_crc {
return Err(anyhow!("MVCC logical log header checksum mismatch"));
}
Ok(())
}
fn initial_mvcc_log_crc(log: &[u8]) -> Result<u32> {
let salt = u64::from_le_bytes(
log[MVCC_LOG_HEADER_SALT_START..MVCC_LOG_HEADER_SALT_END]
.try_into()View on GitHub (pinned to bad083fafb)
Solutions
- Re-pull the logical log from the producer; nonzero reserved bytes mean the header was altered or written by a different format.
- Verify both sync endpoints run the same Turso build; a build that populates reserved fields will always be rejected here.
- Hexdump bytes 16-51 and confirm they are zero to distinguish corruption from format divergence.
- If building test logs programmatically, zero the whole 56-byte header before filling known fields.
Example fix
// before
let snapshot = scan_mvcc_log(&log)?; // errors: reserved bytes must be zero
// after: pre-check reserved bytes and treat failure as a corrupt header
let reserved_zero = log
.get(MVCC_LOG_HEADER_RESERVED_START..MVCC_LOG_HEADER_CRC_START)
.is_some_and(|bytes| bytes.iter().all(|b| *b == 0));
anyhow::ensure!(reserved_zero, "MVCC log header reserved bytes nonzero; re-pull the log");
let snapshot = scan_mvcc_log(&log)?; Defensive patterns
Strategy: validation
Validate before calling
fn mvcc_reserved_bytes_zero(log: &[u8]) -> bool {
log.get(16..52).is_some_and(|bytes| bytes.iter().all(|b| *b == 0))
}
// run before scan_mvcc_log:
anyhow::ensure!(mvcc_reserved_bytes_zero(&log), "reserved header bytes nonzero; re-pull"); Type guard
fn mvcc_reserved_bytes_zero(log: &[u8]) -> bool {
log.get(16..52).is_some_and(|bytes| bytes.iter().all(|b| *b == 0))
} Try / catch
match scan_mvcc_log(&log) {
Ok(snapshot) => { /* proceed */ }
Err(err) if err.to_string().contains("reserved bytes must be zero") => {
// header written by a divergent format or tampered: re-pull the log
}
Err(err) => return Err(err),
} Prevention
- Do not run forked builds that store data in reserved header fields.
- Zero-initialize header buffers when generating logs in tests.
- Hash-verify logs after every copy between nodes.
- Keep both sync endpoints on the same engine revision.
When it happens
Trigger: scan_mvcc_log(&log) where any byte in header range [16,52) is nonzero: a fork or patched build that stashes fields in reserved space, post-write corruption that survives the magic, version, flags, and length checks, or a hand-crafted test log that forgot to zero the reserved span.
Common situations: Running a patched or forked Turso build that populates reserved header bytes; logs damaged in transit (interrupted and resumed rsync/SCP); test fixtures built by hand without zeroed reserved bytes; bit rot confined to the middle of the header.
Related errors
- invalid MVCC logical log header length: {header_len}
- MVCC logical log extension record count without extension bl
- MVCC logical log extension block missing flag at offset {off
- MVCC logical log header checksum mismatch
- invalid MVCC logical log frame magic at offset {offset}: {fr
AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16).
Data as JSON: /api/errors/92fe48dec41795ef.
Report an issue: GitHub.