astrid-runtime/astrid · error · io::Error

volume seek overflow

Error message

volume seek overflow

What it means

seek() computes the new cursor in i128 and returns InvalidInput ('volume seek overflow') when the arithmetic would overflow, specifically for SeekFrom::Current and SeekFrom::End additions that exceed the checked_add domain.

Solutions

  1. Validate offset/delta values before seeking and clamp to 0..=region_len
  2. Use SeekFrom::Start with a bounded offset instead of large Current/End deltas
  3. Compute the intended target in checked arithmetic in the caller first
  4. Fix upstream code that passes sentinel/marker values (u64::MAX) as deltas

Example fix

// before
let pos = reader.seek(std::io::SeekFrom::Current(i64::MAX))?;
// after
let target = (cursor as i128 + delta as i128).clamp(0, region_len as i128) as u64;
let pos = reader.seek(std::io::SeekFrom::Start(target))?;
Defensive patterns

Strategy: validation

Validate before calling

fn safe_target(cursor: u64, delta: i64, region_len: u64) -> Option<u64> {
    let t = cursor as i128 + delta as i128;
    u64::try_from(t).ok().filter(|&t| t <= region_len)
}

Type guard

fn seekable(offset: i128, region_len: u64) -> bool { (0..=region_len as i128).contains(&offset) }

Try / catch

match reader.seek(SeekFrom::Current(delta)) {
    Err(e) if e.kind() == std::io::ErrorKind::InvalidInput => return Err(MyError::SeekOutOfBounds),
    other => other?,
}

Prevention

When it happens

Trigger: SeekFrom::Current(delta) where cursor + delta overflows i64/i128 range; SeekFrom::End(delta) where region_len + delta overflows, e.g. extremely large delta values or u64::MAX offsets.

Common situations: Computing seek targets from unvalidated external offsets; using sentinel values like u64::MAX as deltas; corrupt metadata producing absurd region_len-derived targets.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/aace12aa2fa9a130. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-storage/src/volume.rs:419

                .map_err(|_| io::Error::other("volume write length overflow"))?,
            &mut &bytes[..],
        )?;
        Ok(bytes.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        self.volume.sync()
    }
}

impl Seek for VolumeFile {
    fn seek(&mut self, position: SeekFrom) -> io::Result<u64> {
        let next = match position {
            SeekFrom::Start(offset) => i128::from(offset),
            SeekFrom::Current(delta) => i128::from(self.cursor)
                .checked_add(i128::from(delta))
                .ok_or_else(|| {
                    io::Error::new(io::ErrorKind::InvalidInput, "volume seek overflow")
                })?,
            SeekFrom::End(delta) => i128::from(self.volume.region_len(&self.region)?)
                .checked_add(i128::from(delta))
                .ok_or_else(|| {
                    io::Error::new(io::ErrorKind::InvalidInput, "volume seek overflow")
                })?,
        };
        self.cursor = u64::try_from(next)
            .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "negative volume seek"))?;
        Ok(self.cursor)
    }
}

/// Minimal metadata returned for a volume region.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct VolumeMetadata {
    length: u64,
}

View on GitHub (pinned to affd8760f4)