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
The MVCC logical log header reserves a byte range between MVCC_LOG_HEADER_RESERVED_START and MVCC_LOG_HEADER_CRC_START that must be all zeros. validate_mvcc_log_header rejects any nonzero byte there, catching headers written from uninitialized memory or files damaged after the fact.
Solutions
- Restore the MVCC log from a clean backup
- Regenerate the log (delete it; clients fall back to replace-base sync)
- If writing log headers yourself, zero the whole 56-byte buffer before filling fields
Example fix
// before (writer): header built from uninitialized memory let mut header = [0xABu8; MVCC_LOG_HEADER_SIZE]; // reserved bytes stay dirty // after: zeroed buffer, reserved range untouched let mut header = [0u8; MVCC_LOG_HEADER_SIZE]; header[..4].copy_from_slice(&MVCC_LOG_MAGIC.to_le_bytes()); header[4] = MVCC_LOG_VERSION; // bytes 5..CRC start remain zero by construction
Defensive patterns
Strategy: validation
Validate before calling
fn mvcc_reserved_bytes_zero(log: &[u8]) -> bool {
log.len() >= MVCC_LOG_HEADER_CRC_START
&& log[MVCC_LOG_HEADER_RESERVED_START..MVCC_LOG_HEADER_CRC_START]
.iter()
.all(|b| *b == 0)
} Try / catch
// Any header-region error (reserved bytes, flags, length, CRC) is unrecoverable: // quarantine the file and resync clients from the replace-base fallback.
Prevention
- Zero-init header buffers before writing
- Avoid editing the log with external tools
- Monitor for recurring header corruption as an early disk-failure signal
When it happens
Trigger: Any byte in the reserved slice log[MVCC_LOG_HEADER_RESERVED_START..MVCC_LOG_HEADER_CRC_START] is nonzero when a /pull-updates logical pull calls scan_mvcc_log.
Common situations: A writer bug that appends header bytes without zeroing the reserved region; disk corruption; a file reconstructed by hand or by a partial-copy tool that filled gaps with junk.
Related errors
- invalid MVCC logical log header flags
- invalid MVCC logical log header length
- invalid MVCC logical log frame end magic at offset
- invalid MVCC logical log frame magic at offset
- MVCC logical log extension block missing flag at offset
AI-assisted analysis of tursodatabase/turso@492c4a71cd (2026-08-20).
Data as JSON: /api/errors/92fe48dec41795ef.
Report an issue: GitHub.
Appendix: source
Thrown at cli/sync_server.rs:1119
}
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()
.expect("fixed-size salt slice"),View on GitHub (pinned to 492c4a71cd)