tursodatabase/turso · error
invalid MVCC logical log header flags
Error message
invalid MVCC logical log header flags
What it means
Byte 5 of the MVCC logical log header is a flags field where only bit 0 (0x1) is defined; validate_mvcc_log_header requires (log[5] & 0b1111_1110) == 0. The error fires when any other bit is set, which indicates either a corrupted header or a future format revision that assigned new header flag bits this build does not understand.
Solutions
- Restore the MVCC logical log from a known-good backup (single flipped bit or torn write is the usual cause)
- Delete/regenerate the log and let clients resync via replace-base fallback
- If you maintain the writer, verify no build sets header flags beyond bit 0 before shipping a format change
Defensive patterns
Strategy: validation
Validate before calling
fn mvcc_header_flags_ok(log: &[u8]) -> bool {
log.len() > 5 && (log[5] & 0b1111_1110) == 0
} Type guard
fn is_likely_valid_mvcc_header(log: &[u8]) -> bool {
log.len() >= MVCC_LOG_HEADER_SIZE
&& read_u32_le(log, 0) == Ok(MVCC_LOG_MAGIC)
&& log[4] == MVCC_LOG_VERSION
&& (log[5] & 0b1111_1110) == 0
} Try / catch
if let Err(err) = scan_mvcc_log(&log) {
if err.to_string().contains("MVCC logical log header") {
// header-level corruption: quarantine file, alert, fall back to replace-base
}
} Prevention
- Write log headers from zeroed buffers so undefined fields stay zero
- fsync the header before appending frames
- Keep backups of the logical log so corruption means restore, not data loss
When it happens
Trigger: scan_mvcc_log -> validate_mvcc_log_header on a >= 56-byte log whose flags byte at log[5] has any bit above bit 0 set (e.g. 0x02, 0x80) during a POST /pull-updates logical pull.
Common situations: Bit rot or a torn header write after a crash during log creation; running a fork that writes extra header flags against a stock tursodb server; a log file edited or truncated then re-padded manually.
Related errors
- invalid MVCC logical log header length
- MVCC logical log header reserved bytes must be zero
- 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/c1d7b1dcdaf34a6d.
Report an issue: GitHub.
Appendix: source
Thrown at cli/sync_server.rs:1106
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!(
"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]);View on GitHub (pinned to 492c4a71cd)