clockworklabs/SpacetimeDB · error · io::Error
repo {}: segment {} already exists and is non-empty: {}
Error message
repo {}: segment {} already exists and is non-empty: {} What it means
When the streaming writer rolls into a new segment it creates the segment file; creation returned AlreadyExists and the existing file is longer than a bare segment header, i.e. it already contains commits. Only header-only stubs are automatically removed and retried; real data is never silently overwritten, so the operation fails with this error naming the repo and segment offset.
Source
Thrown at crates/commitlog/src/stream/writer.rs:466
let segment_offset = last_written_tx_range
.as_ref()
.map(|range| range.end)
.unwrap_or_default();
let mut segment = loop {
match repo.create_segment(segment_offset, header) {
Ok(segment) => break segment,
Err(e) if e.kind() == io::ErrorKind::AlreadyExists => {
trace!("segment already exists");
let mut s = repo.open_segment_writer(segment_offset)?;
let len = s.segment_len()?;
trace!("segment len: {len}");
if len <= segment::Header::LEN as _ {
trace!("overwriting existing segment");
repo.remove_segment(segment_offset)?;
continue;
}
return Err(io::Error::new(
e.kind(),
format!(
"repo {}: segment {} already exists and is non-empty: {}",
repo, segment_offset, e
),
));
}
Err(e) => return Err(e),
}
};
fallocate(&mut segment, &commitlog_options)?;
let index_writer = repo
.create_offset_index(segment_offset, commitlog_options.offset_index_len())
.inspect_err(|e| warn!("unable to create offset index segment={segment_offset} err={e:?}"))
.map(|index| OffsetIndexWriter::new(index, commitlog_options))
.ok();
View on GitHub (pinned to 524b4487d9)
Solutions
- Clear or move aside the existing commitlog directory before re-bootstrapping.
- Start the replay at a segment offset beyond the segments already present.
- If the existing data is confirmed disposable, delete the named segment file and retry.
- Ensure exactly one writer process per commitlog repo.
Defensive patterns
Strategy: validation
Validate before calling
// Before replay, scan the target repo for existing segments overlapping the range:
for seg_offset in existing_segment_offsets(repo)? {
if replay_range.contains(&seg_offset) {
return Err(format!("repo already holds segment {} in replay range", seg_offset));
}
} Try / catch
match writer.append_all(stream, progress).await {
Err(e) if e.kind() == io::ErrorKind::AlreadyExists => {
// Decide: clear the repo and restart replay, or move the resume point past
// the existing segment. Never blind-retry - the file will still be there.
}
r => r,
} Prevention
- Clear or move aside the commitlog directory before re-bootstrapping.
- Keep one writer process per commitlog repo.
- Automate bootstrap so replay always starts beyond existing segments.
When it happens
Trigger: Replaying a bootstrap/replication stream into a commitlog repo that already contains segments covering the same offset range; running two writers against the same repo concurrently; restoring an old data directory and replaying overlapping history.
Common situations: Re-running follower bootstrap without clearing the data directory; a previous partial replay left segments behind; two nodes misconfigured to share one commitlog path.
Related errors
- AlreadyExists
- repo {}: error getting file metadata for segment {}: {}
- error reading commit header: {e}
- failed to read {} bytes of commit payload: {}
- failed to read checksum: {e}
AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16).
Data as JSON: /api/errors/9f72307fb29bebbd.
Report an issue: GitHub.