astrid-runtime/astrid · error · io::Error
negative volume seek
Error message
negative volume seek
What it means
After the overflow checks, seek() converts the computed i128 position back to u64; a negative result means the seek landed before offset 0, which is invalid, so InvalidInput ('negative volume seek') is returned.
Solutions
- Clamp the requested position to 0 before seeking
- Compute the target in the caller and use SeekFrom::Start(max(0, target))
- Verify bookkeeping of how far back you intend to seek (bytes consumed)
- Handle the InvalidInput error to detect underflow instead of panicking on assumption
Example fix
// before reader.seek(std::io::SeekFrom::Current(-1000))?; // cursor is only 10 // after let target = cursor.saturating_sub(1000); reader.seek(std::io::SeekFrom::Start(target))?;
Defensive patterns
Strategy: validation
Validate before calling
fn rewind_target(cursor: u64, back: u64) -> u64 { cursor.saturating_sub(back) } // use SeekFrom::Start(rewind_target(...)) Type guard
fn can_rewind(cursor: u64, back: u64) -> bool { back <= cursor } Try / catch
match reader.seek(SeekFrom::Current(-back)) {
Err(e) if e.kind() == std::io::ErrorKind::InvalidInput => {
reader.seek(std::io::SeekFrom::Start(0))? // clamp to start
}
other => other?,
} Prevention
- Track bytes consumed so rewind distances never exceed the cursor
- Use saturating_sub plus SeekFrom::Start for backward seeks
- Add assertions that computed positions are >= 0
When it happens
Trigger: SeekFrom::Current(negative delta) or SeekFrom::End(negative delta) whose magnitude exceeds the cursor/region length, e.g. seeking -1000 from Current when cursor is 10.
Common situations: Rewinding past the start due to miscounted bytes read; off-by-one in buffer management; using a recorded delta computed against a different, larger position.
Related errors
- volume seek overflow
- private host-file validation is unavailable on this target
- workspace root is not a directory
- a corpus produced no chunks
- a representation record must cover at least one logical…
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/509deb350a3267ce.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-storage/src/volume.rs:428
}
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,
}
impl VolumeMetadata {
/// Return the logical byte length.
#[must_use]
pub const fn len(self) -> u64 {
self.length
}
/// A volume region is always a regular byte stream.View on GitHub (pinned to affd8760f4)