{"record":{"id":"337ef0cf0e69ed83","repo":"pola-rs/polars","slug":"cannot-use-offsetted-on-a-negative-slice","errorCode":null,"errorMessage":"cannot use offsetted() on a negative slice","messagePattern":"cannot use offsetted\\(\\) on a negative slice","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/polars-utils/src/slice_enum.rs","lineNumber":66,"sourceCode":"    /// Returns the end position of the slice (offset + len).\n    ///\n    /// # Panics\n    /// Panics if self is negative.\n    pub fn end_position(&self) -> usize {\n        let Slice::Positive { offset, len } = self.clone() else {\n            panic!(\"cannot use end_position() on a negative slice\");\n        };\n\n        offset.saturating_add(len)\n    }\n\n    /// Returns the equivalent slice to apply from an offsetted position.\n    ///\n    /// # Panics\n    /// Panics if self is negative.\n    pub fn offsetted(self, position: usize) -> Self {\n        let Slice::Positive { offset, len } = self else {\n            panic!(\"cannot use offsetted() on a negative slice\");\n        };\n\n        let (offset, len) = if position <= offset {\n            (offset - position, len)\n        } else {\n            let n_past_offset = position - offset;\n            (0, len.saturating_sub(n_past_offset))\n        };\n\n        Slice::Positive { offset, len }\n    }\n\n    /// Restricts the bounds of the slice to within a number of rows. Negative slices will also\n    /// be translated to the positive equivalent.\n    pub fn restrict_to_bounds(self, n_rows: usize) -> Self {\n        match self {\n            Slice::Positive { offset, len } => {\n                let offset = offset.min(n_rows);","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/pola-rs/polars/blob/fe841f959ef4d2ceefc05a310d33ed7b1ab24e5e/crates/polars-utils/src/slice_enum.rs#L48-L84","documentation":"Slice::offsetted only works on Slice::Positive; applying an offset from a negative slice panics because the absolute start position of a from-the-end slice is undefined until it is materialized against an actual length.","triggerScenarios":"Calling offsetted() on a Slice::Negative, e.g. when chaining window/slice operations where an earlier slice was negative.","commonSituations":"Composition of slice operations (offset then slice again) where one input slice came from negative indexing; refactors that removed an earlier variant check.","solutions":["Ensure the slice is Slice::Positive before calling offsetted(); convert negative slices first","Match on the enum and implement negative handling at the call site","Track slice provenance so negative slices are resolved once, early, against a known length"],"exampleFix":"// before\nlet shifted = slice.offsetted(pos);\n// after\nlet shifted = match slice {\n    s @ Slice::Positive { .. } => s.offsetted(pos),\n    Slice::Negative { .. } => resolve_to_positive(slice, total_len).offsetted(pos),\n};","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"fn offset_slice(s: Slice, pos: usize, total_len: usize) -> Slice {\n    match s { Slice::Positive { .. } => s.offsetted(pos), Slice::Negative { .. } => resolve(s, total_len).offsetted(pos) }\n}","tryCatchPattern":null,"preventionTips":["Resolve negative slices once, early, against a known sequence length","Keep slice transformations in a single utility module with exhaustive matches","Cover chained slice/offset operations in tests with negative inputs"],"tags":["rust","panic","invalid-state","slices"],"backgroundTag":"invalid-state-transition","analyzedSha":"fe841f959ef4d2ceefc05a310d33ed7b1ab24e5e","analyzedAt":"2026-09-18T22:14:11.667Z","contentChangedAt":"2026-09-18T22:14:11.667Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}