{"record":{"id":"fb08f379a8f355d0","repo":"clockworklabs/SpacetimeDB","slug":"invalidinput-fb08f3","errorCode":"InvalidInput","errorMessage":"invalid seek to a negative or overflowing position","messagePattern":"invalid seek to a negative or overflowing position","errorType":"validation","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/commitlog/src/repo/mem/segment.rs","lineNumber":167,"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 _)\n    }\n}\n\nimpl FileLike for Segment {\n    fn fsync(&mut self) -> io::Result<()> {\n        Ok(())\n    }\n","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/524b4487d949b61a07d4f39c862d1290259dfd20/crates/commitlog/src/repo/mem/segment.rs#L149-L185","documentation":"A Seek on an in-memory segment computed a target position that is negative (before byte 0) or overflows u64, so checked_add_signed failed (InvalidInput). This mirrors std's seek semantics: SeekFrom::Start(n) never fails here; only End/Current arithmetic can. The segment's own state is unchanged.","triggerScenarios":"seek(SeekFrom::End(-n)) with n greater than the segment length; seek(SeekFrom::Current(negative)) that would move before position 0; relative skips computed from untrusted or underflowing i64 offsets.","commonSituations":"Replay/scan code that rewinds by a delta larger than the file; converting external i64 offsets into seeks without clamping.","solutions":["Compute the absolute target with checked/saturating u64 arithmetic first, then seek with SeekFrom::Start","Clamp rewind amounts: target = len.saturating_sub(rewind)","Validate externally sourced offsets against the segment length before seeking"],"exampleFix":"// before\nreader.seek(io::SeekFrom::End(-(skip as i64)))?; // fails when skip > len\n\n// after\nlet len = reader.seek(io::SeekFrom::End(0))?;\nlet target = len.saturating_sub(skip);\nreader.seek(io::SeekFrom::Start(target))?;","handlingStrategy":"validation","validationCode":"// compute absolute targets instead of relative seeks\nfn rewind_to(reader: &mut impl io::Seek, skip: u64) -> io::Result<u64> {\n    let len = reader.seek(io::SeekFrom::End(0))?;\n    let target = len.saturating_sub(skip); // clamp at 0\n    reader.seek(io::SeekFrom::Start(target))\n}","typeGuard":"fn is_invalid_seek(e: &io::Error) -> bool {\n    e.kind() == io::ErrorKind::InvalidInput\n        && e.to_string().contains(\"invalid seek to a negative or overflowing position\")\n}","tryCatchPattern":null,"preventionTips":["Prefer SeekFrom::Start with a pre-computed u64 over End/Current with i64 deltas","Use checked_add/checked_sub/saturating arithmetic on offsets sourced from external input"],"tags":["rust","commitlog","memory-repo","seek","invalid-input","arithmetic-overflow"],"backgroundTag":"invalid-seek-offset","analyzedSha":"524b4487d949b61a07d4f39c862d1290259dfd20","analyzedAt":"2026-08-16T23:58:54.611Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}