clockworklabs/SpacetimeDB · error · io::Error
InvalidData
InvalidData
Error message
repo {}: too many empty segments: {} What it means
On repository open, the commitlog scans the newest segments and tolerates at most one empty (zero-transaction) segment, which a single crash can leave behind. More than one consecutive empty segment yields `CommittedMeta::Prefix` whose error is InvalidData 'repo {name}: too many empty segments: {n}' — the log still opens, but only up to the recovered prefix. Repeated crash-loops that never commit are the typical producer.
Source
Thrown at crates/commitlog/src/commitlog.rs:476
mut segment_reader,
}) = open_newest_non_empty_segment(&repo)?
else {
return Ok(None);
};
let offset_index = repo.get_offset_index(segment_offset).ok();
match segment::Metadata::extract(segment_offset, &mut segment_reader, offset_index.as_ref()) {
// Segment is intact.
Ok(metadata) if empty_segments <= 1 => {
assert!(
!metadata.tx_range.is_empty(),
"segment was promised to be non-empty but contains zero transactions"
);
Ok(Some(CommittedMeta::Complete { metadata }))
}
// Segment is good, but there are too many empty segments.
Ok(metadata) => Ok(Some(CommittedMeta::Prefix {
metadata,
error: io::Error::new(
io::ErrorKind::InvalidData,
format!("repo {}: too many empty segments: {}", repo, empty_segments),
),
})),
// Segment is non-empty, but first commit is corrupt.
Err(error::SegmentMetadata::InvalidCommit { sofar, source }) if sofar.tx_range.is_empty() => {
Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"repo {}: first commit in the most recent segment is corrupt: {}",
repo, source
),
))
}
// Some prefix of the segment is good.
Err(error::SegmentMetadata::InvalidCommit { sofar, source }) => Ok(Some(CommittedMeta::Prefix {
metadata: sofar,
error: source,View on GitHub (pinned to 524b4487d9)
Solutions
- Fix the crash loop first (OOM, startup panic) — each failed restart adds another empty segment
- Move aside or delete the trailing empty segment files, keeping at most one
- Reopen the repository; it recovers to the prefix and new commits re-extend the log
Defensive patterns
Strategy: try-catch
Try / catch
match open_repository(cfg) {
Ok((log, CommittedMeta::Prefix { error, .. })) => {
// opened at a prefix: "too many empty segments" is a crash-loop signature;
// investigate before more empty segments accumulate
tracing::warn!("commitlog opened at prefix: {error}");
}
Ok((_log, CommittedMeta::Complete { .. })) => { /* normal recovery */ }
Err(e) => return Err(e),
} Prevention
- Alert on repeated host restarts with no commits — each adds an empty segment
- Fix startup crash loops (OOM, panics) before reopening the database
- When pruning manually, keep at most one trailing empty segment
When it happens
Trigger: Opening a repository whose newest consecutive segments contain zero transactions, with count greater than 1 — several crash-restart cycles each creating a segment with no commit.
Common situations: Host crash-looping (OOM killer, startup panic, container restart storm) — every restart that opens a new segment without committing adds one empty segment.
Related errors
- error reading commit header: {e}
- failed to read {} bytes of commit payload: {}
- failed to read checksum: {e}
- InvalidInput
- InvalidInput
AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16).
Data as JSON: /api/errors/7d9e8dc44a12c8c9.
Report an issue: GitHub.