{"record":{"id":"b746ccea699d4d41","repo":"pola-rs/polars","slug":"index-key-is-out-of-bounds-for-dataframe-of-heig","errorCode":null,"errorMessage":"index {key} is out of bounds for DataFrame of height {num_rows}","messagePattern":"index (.+?) is out of bounds for DataFrame of height (.+?)","errorType":"exception","errorClass":"IndexError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/_utils/getitem.py","lineNumber":299,"sourceCode":"\n\n@overload\ndef _select_rows(df: DataFrame, key: SingleIndexSelector) -> Series: ...\n\n\n@overload\ndef _select_rows(df: DataFrame, key: MultiIndexSelector) -> DataFrame: ...\n\n\ndef _select_rows(\n    df: DataFrame, key: SingleIndexSelector | MultiIndexSelector\n) -> DataFrame | Series:\n    \"\"\"Select one or more rows from the DataFrame.\"\"\"\n    if isinstance(key, int):\n        num_rows = df.height\n        if (key >= num_rows) or (key < -num_rows):\n            msg = f\"index {key} is out of bounds for DataFrame of height {num_rows}\"\n            raise IndexError(msg)\n        return df.slice(key, 1)\n\n    if isinstance(key, slice):\n        return _select_rows_by_slice(df, key)\n\n    elif isinstance(key, range):\n        key = range_to_slice(key)\n        return _select_rows_by_slice(df, key)\n\n    elif isinstance(key, Sequence):\n        if not key:\n            return df.clear()\n        if isinstance(key[0], bool):\n            _raise_on_boolean_mask()\n        s = pl.Series(\"\", key, dtype=Int64)\n        indices = _convert_series_to_indices(s, df.height)\n        return _select_rows_by_index(df, indices)\n","sourceCodeStart":281,"sourceCodeEnd":317,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/_utils/getitem.py#L281-L317","documentation":"_select_rows (getitem.py:299) bounds-checks integer row keys before slicing: a single-int key must satisfy -df.height <= key < df.height (checked as key >= num_rows or key < -num_rows). Out-of-range indices raise this IndexError because the row is fetched with df.slice(key, 1), which cannot silently return nothing.","triggerScenarios":"df[10] on a 3-row frame; df[-7] on a 3-row frame; df[0] or df[i, 'a'] on a frame left empty after a filter/collect; i taken from range(len(bigger_df)).","commonSituations":"Off-by-one after head()/filter()/join() shrank the frame; indices captured before a transformation and reused after; iterating with a stale length after dropping rows.","solutions":["Bounds-check before access: 0 <= i < df.height or -df.height <= i < 0","Use df.slice(i, n), df.head(n), or df.tail(n) which clamp instead of raising","Recompute positions after transformations, or key rows with df.with_row_index('i') and filter on it"],"exampleFix":"# before\nrow = df[i]            # IndexError after filtering shrank df\n\n# after\nrow = df[i] if -df.height <= i < df.height else None","handlingStrategy":"validation","validationCode":"i = int(i)\nif not (-df.height <= i < df.height):\n    raise IndexError(f\"row {i} out of range for height {df.height}\")\nrow = df[i]","typeGuard":"def in_row_bounds(df, i: int) -> bool:\n    return -df.height <= i < df.height","tryCatchPattern":"try:\n    row = df[i]\nexcept IndexError:\n    row = None  # or log and skip","preventionTips":["Check df.height before single-row access, especially after filters","Use df.slice/head/tail for clamping semantics instead of raw ints","Attach with_row_index and filter by it rather than carrying stale positions"],"tags":["python","polars","dataframe","indexing","out-of-bounds","indexerror"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}