clockworklabs/SpacetimeDB · error · io::Error

write position overflow

Error message

write position overflow

What it means

While writing to an in-memory commitlog Segment, the implementation computes requested_end = self.pos + buf.len() as u64. checked_add returns None only when that sum would exceed u64::MAX, and the write fails with ErrorKind::InvalidInput, 'write position overflow'. In practice this is a defensive guard: reaching it requires the write position to be within buf.len() of u64::MAX, which real logs never approach.

Source

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

        Self { pos: 0, storage, space }
    }

    fn len(&self) -> usize {
        self.storage.read().unwrap().len()
    }
}

impl io::Write for Segment {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        if buf.is_empty() {
            return Ok(0);
        }

        let mut storage = self.storage.write().unwrap();
        let requested_end = self
            .pos
            .checked_add(buf.len() as u64)
            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "write position overflow"))?;

        if requested_end > storage.alloc {
            let mut avail = self.space.lock().unwrap();

            if self.pos >= storage.alloc {
                let minimum_alloc = next_page_multiple(
                    self.pos
                        .checked_add(1)
                        .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "write position overflow"))?,
                )?;
                let needed = minimum_alloc - storage.alloc;
                if *avail < needed {
                    return Err(enospc());
                }
            }

            let target_alloc = next_page_multiple(requested_end)?;
            let wanted = target_alloc - storage.alloc;

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Don't seek a Segment to extreme positions before writing in tests; keep positions realistic
  2. If hit in test fixtures, reset/truncate the segment position before large writes
  3. Treat hitting this in production as data corruption — inspect how the position became huge

Example fix

// before
seg.seek(io::SeekFrom::Start(u64::MAX - 2))?;
seg.write_all(&[0u8; 16])?; // InvalidInput: write position overflow

// after
seg.seek(io::SeekFrom::Start(0))?;
seg.write_all(&[0u8; 16])?;
Defensive patterns

Strategy: validation

Validate before calling

const MAX_WRITE_END: u64 = u64::MAX - (1 << 20); // keep 1 MiB headroom
fn fits(pos: u64, len: usize) -> bool {
    pos.checked_add(len as u64).map_or(false, |end| end <= MAX_WRITE_END)
}

Try / catch

match seg.write(buf) {
    Err(ref e) if e.kind() == std::io::ErrorKind::InvalidInput
        && e.to_string().contains("write position overflow") => {
        // position corrupted / test fixture at u64::MAX: reset position
        seg.seek(io::SeekFrom::Start(0))?;
    }
    r => r?,
}

Prevention

When it happens

Trigger: Writing with a write position (self.pos) close to u64::MAX — essentially only in adversarial unit tests or after seeking a Segment to near-u64::MAX and then writing; a corrupted/mis-seeded position value in a hand-constructed test fixture.

Common situations: Test code that seeks to u64::MAX-1 and writes; essentially unreachable in production because the space budget (enospc) and real data sizes bound pos far below 2^64.

Related errors


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