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

segment {offset} does not exist

Error message

segment {offset} does not exist

What it means

In-memory Memory::open_segment_writer (and, by delegation, open_segment_reader) failed because no segment exists in the map at the given offset; the BTreeMap lookup miss is converted to io::ErrorKind::NotFound with this message. It signals offset bookkeeping pointing at a segment that was never created or has been removed - on the filesystem repo the OS returns the equivalent NotFound from opening a nonexistent file.

Source

Thrown at crates/commitlog/src/repo/mem.rs:85

                        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_writer(&self, offset: u64) -> io::Result<Self::SegmentWriter> {
        let inner = self.segments.read().unwrap();
        let Some(buf) = inner.get(&offset) else {
            return Err(io::Error::new(
                io::ErrorKind::NotFound,
                format!("segment {offset} does not exist"),
            ));
        };
        Ok(Segment::from_shared(self.space.clone(), buf.clone()))
    }

    fn open_segment_reader(&self, offset: u64) -> io::Result<Self::SegmentReader> {
        self.open_segment_writer(offset).map(Into::into)
    }

    fn remove_segment(&self, offset: u64) -> io::Result<()> {
        let mut inner = self.segments.write().unwrap();
        if inner.remove(&offset).is_none() {
            return Err(io::Error::new(
                io::ErrorKind::NotFound,
                format!("segment {offset} does not exist"),
            ));

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Create the segment before opening it - track the set of live offsets in the harness.
  2. Re-check offset arithmetic: after N commits the next segment offset is head.min_tx_offset + head commit count, not a file index.
  3. If the segment was removed deliberately, stop referencing that offset.

Example fix

// before
let seg = repo.open_segment_writer(next_offset)?; // NotFound: never created

// after
let seg = repo.create_segment(next_offset, header)?;
let seg = repo.open_segment_writer(next_offset)?; // open only after create
Defensive patterns

Strategy: try-catch

Try / catch

match repo.open_segment_writer(off) {
    Ok(seg) => seg,
    Err(e) if e.kind() == std::io::ErrorKind::NotFound => repo.create_segment(off, hdr)?,
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Opening a segment offset that was never created (or was removed) on a Memory repo: opening the head before the first create_segment, computing an offset from the wrong base, or reopening a segment after remove_segment.

Common situations: Test harnesses that assume a segment exists after truncation/removal; offset math that forgets a head segment starts at its min_tx_offset rather than zero after rollover.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20). Data as JSON: /api/errors/08744408edc8efa1. Report an issue: GitHub.