pola-rs/polars · error

cannot convert negative slice into range

Error message

cannot convert negative slice into range

What it means

The From<Slice> for Range<usize> conversion hits unwrap() on checked_add when converting a slice whose offset+len overflows usize and no sentinel (len == usize::MAX meaning 'to the end') applies — an overflowing/impossible slice cannot be expressed as a Range.

Solutions

  1. Resolve negative slices against the collection length before converting to a range
  2. Match on the Slice enum and build the range yourself for Slice::Negative
  3. Restrict inputs to non-negative slices at the boundary where users provide them

Example fix

// before
let range: Range<usize> = slice.into();
// after
let range = match slice {
    Slice::Positive { offset, len } => offset..offset + len,
    Slice::Negative { offset, len } => (total_len - offset - len)..(total_len - offset),
};
Defensive patterns

Strategy: type-guard

Type guard

def slice_to_range(s, total_len):
    if s.is_negative():
        return Range(total_len - s.offset - s.len, total_len - s.offset)
    return Range(s.offset, s.offset + s.len)

Prevention

When it happens

Trigger: Converting a Slice::Negative to a Range (e.g. via .into() or From), typically when a slice expression like [:-3] reached code that materializes ranges.

Common situations: Passing user-supplied negative slice bounds into APIs that build ranges internally; iterating rows with slice.to_range() on negative slices.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of pola-rs/polars@fe841f959e (2026-09-18). Data as JSON: /api/errors/9775d39c80a7612a. Report an issue: GitHub.

Appendix: source

Thrown at crates/polars-utils/src/slice_enum.rs:171

                -i128::try_from(offset_from_end).unwrap(),
                i128::try_from(len).unwrap(),
            ),
        }
    }
}

impl From<Slice> for Range<usize> {
    fn from(value: Slice) -> Self {
        match value {
            Slice::Positive { offset, len } => {
                offset
                    ..offset
                        .checked_add(len)
                        // Infer if no len was specified, in which case we set to range end to the max possible.
                        .or((len == usize::MAX).then_some(usize::MAX))
                        .unwrap()
            },
            Slice::Negative { .. } => panic!("cannot convert negative slice into range"),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Slice;

    #[test]
    fn test_slice_offset() {
        assert_eq!(
            Slice::Positive { offset: 3, len: 10 }.offsetted(1),
            Slice::Positive { offset: 2, len: 10 }
        );
        assert_eq!(
            Slice::Positive { offset: 3, len: 10 }.offsetted(5),
            Slice::Positive { offset: 0, len: 8 }
        );

View on GitHub (pinned to fe841f959e)