{"record":{"id":"f32b747524378e04","repo":"clockworklabs/SpacetimeDB","slug":"invalid-seek-to-a-negative-or-overflowing-position-f32b74","errorCode":null,"errorMessage":"invalid seek to a negative or overflowing position","messagePattern":"invalid seek to a negative or overflowing position","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/dst/src/sim/commitlog.rs","lineNumber":356,"sourceCode":"    }\n}\n\nimpl io::Seek for Segment {\n    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {\n        let (base_pos, offset) = match pos {\n            io::SeekFrom::Start(n) => {\n                self.pos = n;\n                return Ok(n);\n            }\n            io::SeekFrom::End(n) => (self.len() as u64, n),\n            io::SeekFrom::Current(n) => (self.pos, n),\n        };\n        match base_pos.checked_add_signed(offset) {\n            Some(n) => {\n                self.pos = n;\n                Ok(n)\n            }\n            None => Err(io::Error::new(\n                io::ErrorKind::InvalidInput,\n                \"invalid seek to a negative or overflowing position\",\n            )),\n        }\n    }\n}\n\nimpl SegmentLen for Segment {\n    fn segment_len(&mut self) -> io::Result<u64> {\n        Ok(self.len() as u64)\n    }\n}\n\nimpl FileLike for Segment {\n    fn fsync(&mut self) -> io::Result<()> {\n        Ok(())\n    }\n","sourceCodeStart":338,"sourceCodeEnd":374,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/6dee26c6efc2856793e12b148a59742964f5d783/crates/dst/src/sim/commitlog.rs#L338-L374","documentation":"Segment implements io::Seek by translating SeekFrom::End/Current into base_pos + signed offset via checked_add_signed. SeekFrom::Start(n) always succeeds (any u64 is a valid absolute position in the in-memory store). For End/Current seeks, if the signed offset makes the result negative or exceed u64::MAX, the seek returns ErrorKind::InvalidInput, 'invalid seek to a negative or overflowing position', mirroring std's own Cursor seek semantics.","triggerScenarios":"seek(SeekFrom::Current(negative)) when the current position is smaller than |offset| (would go below zero); seek(SeekFrom::End(negative)) past the start of the data; seek with a positive offset that overflows u64 from a large base; rewinding a fresh, zero-length segment with SeekFrom::End(-1) or more.","commonSituations":"Generic log-reading code that rewinds by a fixed byte count (e.g. re-reading a trailer/record header) without checking it cannot precede the segment start; parsers computing offsets from untrusted length prefixes; copying std::io::Cursor patterns onto Segment.","solutions":["Clamp negative rewinds: use seek(SeekFrom::Current(-n)) only after verifying pos >= n, or compute the absolute target and use SeekFrom::Start","Validate lengths/offsets parsed from the data before turning them into seek offsets","For End-relative seeks, confirm segment len >= |negative offset|"],"exampleFix":"// before\nseg.seek(io::SeekFrom::Current(-(header_len as i64)))?; // InvalidInput if pos < header_len\n\n// after\nlet pos = seg.stream_position()?;\nlet target = pos.checked_sub(header_len as u64)\n    .ok_or_else(|| anyhow!(\"record header crosses segment start\"))?\n    .min(seg.stream_len()?);\nseg.seek(io::SeekFrom::Start(target))?;","handlingStrategy":"validation","validationCode":"async fn checked_seek<S: std::io::Seek + std::io::Read>(s: &mut S, target: i64) -> std::io::Result<u64> {\n    let (base, len) = (s.stream_position()?, s.stream_len()?);\n    let abs = i128::from(base) + i128::from(target);\n    anyhow::ensure!((0..=i128::from(len)).contains(&abs), \"seek out of range\");\n    s.seek(std::io::SeekFrom::Start(abs as u64))\n}","typeGuard":null,"tryCatchPattern":"match seg.seek(io::SeekFrom::Current(off)) {\n    Ok(p) => p,\n    Err(ref e) if e.kind() == std::io::ErrorKind::InvalidInput => {\n        return Err(anyhow::anyhow!(\"rewound past segment start (pos={}, off={})\", pos, off));\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Prefer absolute SeekFrom::Start with a validated target over negative relative seeks","Validate length prefixes parsed from log records before using them as offsets","Clamp rewinds: min(requested, current_position)"],"tags":["commitlog","storage","rust","seek","simulation"],"backgroundTag":"invalid-seek-offset","analyzedSha":"6dee26c6efc2856793e12b148a59742964f5d783","analyzedAt":"2026-08-20T06:08:37.179Z","contentChangedAt":"2026-08-20T06:08:37.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}