clockworklabs/SpacetimeDB · critical · std::io::Error

repo {}: first commit in the most recent segment is corrupt:

Error message

repo {}: first commit in the most recent segment is corrupt: {}

What it means

Hard recovery failure from CommittedMeta::extract: while extracting metadata for the most recent non-empty segment, the very first commit failed to decode. Because no earlier commit in that segment survived, there is no prefix to fall back to, so the function returns InvalidData instead of a CommittedMeta::Prefix. Typically the first commit of a fresh segment was torn by a crash mid-write, or the segment's first bytes are corrupted.

Source

Thrown at crates/commitlog/src/commitlog.rs:483

            // 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,
            })),
            // Something went wrong, including out-of-order errors and such.
            Err(error::SegmentMetadata::Io(e)) => Err(e),
        }
    }
}

View on GitHub (pinned to 9e0d92412f)

Solutions

  1. Delete (or move aside) the damaged newest segment file and let the log continue from the previous segment - commits in that segment are lost, older segments are untouched.
  2. If the data matters, restore the data directory from a snapshot or replica instead of dropping the segment.
  3. Prevent recurrence: graceful shutdowns, durable disk, no external truncation of segment files.
Defensive patterns

Strategy: fallback

Try / catch

let meta = match committed_meta(repo.clone()) {
    Ok(m) => m,
    Err(e) if e.kind() == io::ErrorKind::InvalidData => {
        // newest segment's first commit is torn: quarantine it and retry open once
        quarantine_newest_segment(&repo)?;
        committed_meta(repo)?
    }
    Err(e) => return Err(e.into()),
};

Prevention

When it happens

Trigger: The node crashed while writing the first commit of a newly created segment (header written, payload or checksum missing); or the first bytes of the newest segment were corrupted on disk. Reopening the log cannot salvage that segment.

Common situations: Power loss or kill -9 right after segment rollover; bit rot on the newest segment; partially copied or restored data directories.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@9e0d92412f (2026-08-20). Data as JSON: /api/errors/bb207cc3219e08b4. Report an issue: GitHub.