tursodatabase/turso · critical
truncated MVCC logical log header: len=
Error message
truncated MVCC logical log header: len={} header_size={} What it means
scan_mvcc_log found the .db-log file non-empty but shorter than the fixed MVCC log header size, so it cannot even read magic/version/flags. This indicates a truncated or corrupted logical log: a partial write, a crash during log creation, or a foreign/wrong file sitting at the .db-log path.
Solutions
- Restore the database and .db-log together from a consistent backup
- If the database itself is intact and disposable, delete the invalid .db-log and let clients re-bootstrap (server rebuilds the log)
- Check disk space and filesystem health to stop recurrence
Defensive patterns
Strategy: fallback
Validate before calling
// pre-flight before serving logical pulls
let meta = std::fs::metadata(&log_path)?;
if 0 < meta.len() && (meta.len() as usize) < MVCC_LOG_HEADER_SIZE {
return Err(anyhow!("logical log file is truncated; restore or delete it and re-bootstrap"));
} Try / catch
match scan_mvcc_log(&log_bytes) {
Ok(snapshot) => snapshot,
Err(e) if e.to_string().contains("truncated MVCC logical log header") => {
// log is unusable: rebuild from the authoritative database and force client re-bootstrap
regenerate_logical_log()?;
scan_mvcc_log(&std::fs::read(&log_path)?)?
}
Err(e) => return Err(e),
} Prevention
- Shut the server down cleanly so the log is never left mid-write
- Restore db and .db-log only as a consistent pair from backups
- Monitor disk space; truncation often follows ENOSPC
When it happens
Trigger: Server hard-killed while the logical log was being created or extended; disk-full truncation; a truncated file copied in as <db>.db-log; then any MVCC logical pull triggers the scan and fails.
Common situations: Power loss or kill -9 during heavy write load; copying files mid-write; filesystem faults; test fixtures with sliced log files.
Related errors
- invalid MVCC logical log frame end magic at offset
- 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
AI-assisted analysis of tursodatabase/turso@492c4a71cd (2026-08-20).
Data as JSON: /api/errors/89e307cee8036acf.
Report an issue: GitHub.
Appendix: source
Thrown at cli/sync_server.rs:1067
.parse::<u64>()
.map_err(|err| anyhow!("invalid MVCC pull revision offset: {revision}: {err}"));
}
// Older page bootstrap responses from this test server used WAL frame
// numbers. Treat them as "the page snapshot already includes the current
// logical log" so the required follow-up logical pull becomes a no-op.
Ok(legacy_default)
}
fn scan_mvcc_log(log: &[u8]) -> Result<MvccLogSnapshot> {
if log.is_empty() {
return Ok(MvccLogSnapshot {
end_offset: 0,
crc_by_offset: vec![(0, 0)],
});
}
if log.len() < MVCC_LOG_HEADER_SIZE {
return Err(anyhow!(
"truncated MVCC logical log header: len={} header_size={}",
log.len(),
MVCC_LOG_HEADER_SIZE
));
}
validate_mvcc_log_header(log)?;
let mut running_crc = initial_mvcc_log_crc(log)?;
let mut offset = MVCC_LOG_HEADER_SIZE;
let mut crc_by_offset = vec![(MVCC_LOG_HEADER_SIZE as u64, running_crc)];
while offset < log.len() {
let Some((frame_end, frame_crc)) = read_mvcc_frame_boundary(log, offset, running_crc)?
else {
break;
};
running_crc = frame_crc;
offset = frame_end;
crc_by_offset.push((offset as u64, running_crc));
}View on GitHub (pinned to 492c4a71cd)