{"record":{"id":"4ee306e50b0bd274","repo":"pola-rs/polars","slug":"negative-stride-is-not-supported-in-conjunction-wi","errorCode":null,"errorMessage":"negative stride is not supported in conjunction with start+stop","messagePattern":"negative stride is not supported in conjunction with start\\+stop","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/_utils/slice.py","lineNumber":142,"sourceCode":"    def apply(self, s: slice) -> LazyFrame:\n        \"\"\"\n        Apply a slice operation.\n\n        Note that LazyFrame is designed primarily for efficient computation and does not\n        know its own length so, unlike DataFrame, certain slice patterns (such as those\n        requiring negative stop/step) may not be supported.\n        \"\"\"\n        start = s.start or 0\n        step = s.step or 1\n\n        # fail on operations that require length to do efficiently\n        if s.stop and s.stop < 0:\n            msg = \"negative stop is not supported for lazy slices\"\n            raise ValueError(msg)\n        if step < 0 and (start > 0 or s.stop is not None) and (start != s.stop):\n            if not (start > 0 > step and s.stop is None):\n                msg = \"negative stride is not supported in conjunction with start+stop\"\n                raise ValueError(msg)\n\n        # ---------------------------------------\n        # empty slice patterns\n        # ---------------------------------------\n        # [:0]\n        # [i:<=i]\n        # [i:>=i:-k]\n        if (step > 0 and (s.stop is not None and start >= s.stop)) or (\n            step < 0\n            and (s.start is not None and s.stop is not None and s.stop >= s.start >= 0)\n        ):\n            return self.obj.clear()\n\n        # ---------------------------------------\n        # straight-through mappings for \"reverse\"\n        # and/or \"gather_every\"\n        # ---------------------------------------\n        # [:]    => clone()","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/_utils/slice.py#L124-L160","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\nlf = pl.scan_csv('data.csv')\nout = lf[5:20:-1]  # ValueError\n\n# after\nout = lf.slice(5, 15).reverse().collect()","handlingStrategy":"validation","validationCode":"def lazy_slice_ok(s: slice) -> bool:\n    start = s.start or 0\n    step = s.step or 1\n    if s.stop is not None and s.stop < 0:\n        return False\n    if step < 0 and (start > 0 or s.stop is not None) and start != s.stop:\n        if not (start > 0 > step and s.stop is None):\n            return False\n    return not (start < 0 and s.stop is not None)","typeGuard":null,"tryCatchPattern":"try:\n    out = lf[s]\nexcept ValueError as e:\n    if 'not supported' in str(e):\n        out = lf.collect()[s]\n    else:\n        raise","preventionTips":["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:]"],"tags":["polars","lazyframe","slicing","valueerror"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}