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

  1. Fix the crash loop first (OOM, startup panic) — each failed restart adds another empty segment
  2. Move aside or delete the trailing empty segment files, keeping at most one
  3. 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

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


AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16). Data as JSON: /api/errors/7d9e8dc44a12c8c9. Report an issue: GitHub.