pola-rs/polars · error · ValueError
negative stride is not supported in conjunction with start+s
Error message
negative stride is not supported in conjunction with start+stop
What it means
Polars' LazyPolarsSlice.apply (py-polars/src/polars/_utils/slice.py:139) rejects Python slice expressions applied to a LazyFrame that use a negative step together with an explicit start and/or stop (e.g. lf[2:8:-1] or lf[:5:-1]). A LazyFrame does not know its row count before collect(), so slices that would need indexing from the end cannot be mapped to efficient lazy operations. Note lf[2::-1] is fine (handled via head+reverse); only start+stop combined with negative stride raises.
Source
Thrown at py-polars/src/polars/_utils/slice.py:142
def apply(self, s: slice) -> LazyFrame:
"""
Apply a slice operation.
Note that LazyFrame is designed primarily for efficient computation and does not
know its own length so, unlike DataFrame, certain slice patterns (such as those
requiring negative stop/step) may not be supported.
"""
start = s.start or 0
step = s.step or 1
# fail on operations that require length to do efficiently
if s.stop and s.stop < 0:
msg = "negative stop is not supported for lazy slices"
raise ValueError(msg)
if step < 0 and (start > 0 or s.stop is not None) and (start != s.stop):
if not (start > 0 > step and s.stop is None):
msg = "negative stride is not supported in conjunction with start+stop"
raise ValueError(msg)
# ---------------------------------------
# empty slice patterns
# ---------------------------------------
# [:0]
# [i:<=i]
# [i:>=i:-k]
if (step > 0 and (s.stop is not None and start >= s.stop)) or (
step < 0
and (s.start is not None and s.stop is not None and s.stop >= s.start >= 0)
):
return self.obj.clear()
# ---------------------------------------
# straight-through mappings for "reverse"
# and/or "gather_every"
# ---------------------------------------
# [:] => clone()View on GitHub (pinned to df599052da)
Solutions
- Materialize first if the data fits: lf.collect()[2:8:-1]
- Rewrite with lazy primitives, e.g. lf.slice(0, 8).slice(2).reverse() or lf.slice(3, 5).reverse() for [3:8:-1]
- For full reversal use lf[::-1] or lf.reverse(), which are supported
- Keep the operation lazy by composing head/tail/slice/gather_every/reverse instead of Python slicing
Example fix
# before
lf = pl.scan_csv('data.csv')
out = lf[5:20:-1] # ValueError
# after
out = lf.slice(5, 15).reverse().collect() Defensive patterns
Strategy: validation
Validate before calling
def lazy_slice_ok(s: slice) -> bool:
start = s.start or 0
step = s.step or 1
if s.stop is not None and s.stop < 0:
return False
if step < 0 and (start > 0 or s.stop is not None) and start != s.stop:
if not (start > 0 > step and s.stop is None):
return False
return not (start < 0 and s.stop is not None) Try / catch
try:
out = lf[s]
except ValueError as e:
if 'not supported' in str(e):
out = lf.collect()[s]
else:
raise Prevention
- Prefer explicit lazy ops (slice/head/tail/reverse/gather_every) over Python slicing on LazyFrame
- Keep slicing helpers DataFrame-only, or validate the slice pattern before applying to a LazyFrame
- Remember supported lazy patterns: [:], [::k], [::-1] / [::-k], [i:], [i:j], [:j], [-i:]
When it happens
Trigger: Calling lf[3:0:-1], lf[:5:-1], lf[1:9:-2], or any LazyFrame __getitem__ where s.step < 0, start != stop, and (start > 0 or s.stop is not None) unless the special case start > 0 > step with s.stop is None. The same slice on a materialized DataFrame works, which surprises users.
Common situations: Porting eager DataFrame slicing code to scan_csv/scan_parquet pipelines; reversing a known window of rows in a lazy query; using generic helper functions that slice both frames with the same slice object.
Related errors
- negative stop is not supported for lazy slices
- the given slice {s!r} is not supported by lazy computation\n
- LazyFrame `how` must be one of {{{allowed}}}, got {how!r}
- `format` must be one of {'binary', 'json'}, got {format!r}
- invalid input for `aggregate_function` argument: {aggregate_
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/4ee306e50b0bd274.
Report an issue: GitHub.