pola-rs/polars · error · ValueError

negative stop is not supported for lazy slices

Error message

negative stop is not supported for lazy slices

What it means

LazyPolarsSlice.apply (polars/_utils/slice.py:138) translates a slice into lazy operations without knowing frame length. A negative stop (lf[10:-5], lf[:-3]) would require resolving the height first, which is not possible efficiently on a LazyFrame, so it fails fast with this ValueError. Positive-stop slices and negative steps without start+stop are fine; a plain DataFrame accepts the same slice.

Source

Thrown at py-polars/src/polars/_utils/slice.py:138

    def __init__(self, obj: LazyFrame) -> None:
        self.obj = obj

    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()

        # ---------------------------------------

View on GitHub (pinned to df599052da)

Solutions

  1. Use explicit lazy methods: lf.limit(n) (head) and lf.tail(n) instead of negative-stop slices
  2. Use a positive stop when the length is known: lf.slice(10, 90)
  3. Collect first if you truly need Python slice semantics: lf.collect()[:-5]

Example fix

# before
lf[:-5]        # negative stop unsupported lazily

# after
lf.tail(5)     # or lf.collect()[:-5]
Defensive patterns

Strategy: validation

Validate before calling

def lazy_slice(lf, start, stop):
    if stop is not None and stop < 0:
        return lf.collect()[:stop].lazy()  # or lf.tail(-stop) for the common case
    return lf[start:stop]

Type guard

def is_lazy_safe_slice(s: slice) -> bool:
    return not (s.stop is not None and s.stop < 0)

Prevention

When it happens

Trigger: lf[:-5]; lf[10:-2]; lf['a'][:-1] on a lazy column expression context; porting df[:-n] code to lazy pipelines.

Common situations: Converting eager pandas-like tail slicing to LazyFrame code; interactive exploration habits applied to lazy queries that will only be resolved at collect().

Related errors


AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16). Data as JSON: /api/errors/b679faabdd7ccafb. Report an issue: GitHub.