clockworklabs/SpacetimeDB · error · io::Error
segment {offset} already exists
Error message
segment {offset} already exists What it means
The in-memory commitlog Repo implementation (crates/dst/src/sim/commitlog.rs) stores segments in a BTreeMap keyed by u64 offset. create_segment returns AlreadyExists when a segment at that offset is already present AND non-empty. Re-creating a segment that exists but is still empty is deliberately allowed (treated as reclaiming crash-recovery scratch space) via Segment::from_shared on the existing storage.
Source
Thrown at crates/dst/src/sim/commitlog.rs:174
impl fmt::Display for Memory {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("<dst-memory>")
}
}
impl Repo for Memory {
type SegmentWriter = Segment;
type SegmentReader = ReadOnlySegment;
fn create_segment(&self, offset: u64, header: Header) -> io::Result<Self::SegmentWriter> {
let mut inner = self.segments.write().unwrap();
let mut segment = match inner.entry(offset) {
btree_map::Entry::Occupied(entry) => {
let entry = entry.get();
if entry.read().unwrap().is_empty() {
Segment::from_shared(self.space.clone(), entry.clone())
} else {
return Err(io::Error::new(
io::ErrorKind::AlreadyExists,
format!("segment {offset} already exists"),
));
}
}
btree_map::Entry::Vacant(entry) => {
let storage = entry.insert(Arc::new(RwLock::new(Storage::new())));
Segment::from_shared(self.space.clone(), storage.clone())
}
};
header.write(&mut segment)?;
Ok(segment)
}
fn open_segment_reader(&self, offset: u64) -> io::Result<Self::SegmentReader> {
self.open_segment_writer(offset).map(Into::into)
}View on GitHub (pinned to 6dee26c6ef)
Solutions
- If the segment already exists and you want to reuse it, call open_segment_writer(offset) instead of create_segment
- Call remove_segment(offset) first when you truly want to recreate it from scratch
- Reset or recreate the Memory repo between replays/tests so state does not leak
- Check your offset math — segments are keyed by exact u64 offset, so an off-by-one lands on a neighbor
Example fix
// before
let seg = repo.create_segment(offset, header)?; // AlreadyExists on replay
// after
let seg = match repo.create_segment(offset, header.clone()) {
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => repo.open_segment_writer(offset)?,
Ok(seg) => seg,
Err(e) => return Err(e),
}; Defensive patterns
Strategy: try-catch
Validate before calling
// Memory repo exposes no exists(); approximate by probing a reader:
fn segment_exists(repo: &Memory, offset: u64) -> bool {
matches!(repo.open_segment_reader(offset), Ok(_))
} Try / catch
let segment = match repo.create_segment(offset, header.clone()) {
Ok(seg) => seg,
Err(ref e) if e.kind() == std::io::ErrorKind::AlreadyExists => {
repo.open_segment_writer(offset)? // reuse existing segment
}
Err(e) => return Err(e.into()),
}; Prevention
- Prefer open_segment_writer when the segment may already exist; reserve create_segment for first creation
- Make replay routines idempotent: create-or-open, never bare create
- Reset the Memory repo between test replays so leftover state cannot collide
- Unit-test the replay path twice in a row to catch non-idempotent creation
When it happens
Trigger: Calling Repo::create_segment(offset, header) twice for the same offset when the first segment has had bytes written or its header written; a log replay/recovery routine that unconditionally recreates segments it discovers; two writers racing to create the same offset in a test harness.
Common situations: Simulator/test harnesses that replay a commit log from scratch without clearing the Memory repo; retry logic that assumes create is idempotent; off-by-one segment-offset computation that collides with an existing segment.
Related errors
- segment {offset} does not exist
- write position overflow
- invalid seek to a negative or overflowing position
- allocation size overflow
- no space left on device
AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20).
Data as JSON: /api/errors/f125d4d9c5db1782.
Report an issue: GitHub.