clockworklabs/SpacetimeDB · error · io::Error

segment {offset} does not exist

Error message

segment {offset} does not exist

What it means

The in-memory commitlog Repo's open_segment_writer (and open_segment_reader, which delegates to it) looks up the requested u64 offset in its BTreeMap of segments. If no segment was ever created (or it was removed) at that offset, it returns io::ErrorKind::NotFound with 'segment {offset} does not exist'. Readers and writers can only be opened for segments that a prior create_segment call established.

Source

Thrown at crates/dst/src/sim/commitlog.rs:197

            }
            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)
    }

    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 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"),
            ));
        }

        Ok(())
    }

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Ensure create_segment(offset, header) has completed successfully before opening readers/writers for that offset
  2. If the segment may legitimately be absent, treat NotFound as end-of-log instead of an error
  3. Verify the offset arithmetic against the segment rotation size used when segments were created
  4. If the segment was removed by remove_segment, recreate it with create_segment before opening

Example fix

// before
let reader = repo.open_segment_reader(offset)?; // NotFound on fresh repo

// after
let reader = match repo.open_segment_reader(offset) {
    Ok(r) => r,
    Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(None), // end of log
    Err(e) => return Err(e),
};
Defensive patterns

Strategy: try-catch

Validate before calling

// Derive the set of offsets you expect, from creation bookkeeping:
let expected: BTreeSet<u64> = created_offsets.iter().copied().collect();
if !expected.contains(&offset) {
    return Ok(None); // no such segment: treat as end-of-log
}

Try / catch

let reader = match repo.open_segment_reader(offset) {
    Ok(r) => r,
    Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
        return Ok(None); // graceful end-of-log
    }
    Err(e) => return Err(e.into()),
};

Prevention

When it happens

Trigger: Calling open_segment_reader/open_segment_writer for an offset before create_segment ran; opening a segment after remove_segment removed it; computing the next segment offset as last_offset + segment_size when the log actually ended at a different boundary; replaying against a fresh/empty Memory repo.

Common situations: Recovery code that assumes a segment exists because it was recorded elsewhere; unit tests forgetting to seed the repo; truncation/rotation logic removing a segment and then a straggler reader trying to open it.

Related errors


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