pandas IndexError: single positional indexer is out-of-bounds (tested)

IndexError: single positional indexer is out-of-bounds means .iloc asked for a row or column position that does not exist, most often .iloc[0] on a filter that matched nothing. We reproduced it, the related "indices are out-of-bounds", and the fixes on pandas 2.3.3 and 3.1.0.

1. Four ways to get it

import pandas as pd

df = pd.DataFrame({"v": [10, 20, 30]})
hits = df[df["v"] > 100]                 # filter matched nothing
try:
    hits.iloc[0]
except IndexError as e:
    print("IndexError:", e)
try:
    df.iloc[[0, 5]]
except IndexError as e:
    print("IndexError:", e)
try:
    df.iloc[:, 1]
except IndexError as e:
    print("IndexError:", e)
try:
    df.take([5])
except IndexError as e:
    print("IndexError:", e)

Output (identical on pandas 2.3.3 and 3.1.0):

IndexError: single positional indexer is out-of-bounds
IndexError: positional indexers are out-of-bounds
IndexError: single positional indexer is out-of-bounds
IndexError: indices are out-of-bounds

iloc and take count positions from 0, so on a 3-row DataFrame the valid rows are 0 to 2 (or -1 to -3) and with one column only column 0 exists. By far the most common cause is the first case: a filter that matched nothing, followed by .iloc[0] on the empty result. A single position gives "single positional indexer is out-of-bounds"; a list gives "positional indexers are out-of-bounds"; take gives "indices are out-of-bounds".

2. Fixes

import pandas as pd

df = pd.DataFrame({"v": [10, 20, 30]})
hits = df[df["v"] > 100]
first = hits.iloc[0] if not hits.empty else None     # guard the empty case
print(first)
print(df["v"].head(1).tolist(), hits["v"].head(1).tolist())   # head never raises
print(df.iloc[0:5]["v"].tolist())                     # slices are clipped, no error
print(df.iloc[-1]["v"])                               # last row

Output (identical on pandas 2.3.3 and 3.1.0):

None
[10] []
[10, 20, 30]
30

Check .empty (or len(df)) before taking the first row, and decide what an empty result should mean for your code. head(1) returns an empty result instead of raising, and slices such as iloc[0:5] are clipped to the rows that exist. Use iloc[-1] for the last row rather than iloc[len(df)]. If you meant a row label rather than a position, use .loc; a missing label raises KeyError instead (see KeyError: 0).

Related: IndexError: list index out of range · KeyError: not in index · merge returns no rows.

Frequently asked questions

What does 'single positional indexer is out-of-bounds' mean?

iloc was given a position past the end of the rows or columns. On an empty DataFrame, even iloc[0] is out of bounds.

How do I safely get the first row of a filtered DataFrame?

Check df.empty first, or use df.head(1), which returns an empty result instead of raising.

What is the difference from 'indices are out-of-bounds'?

Same problem, raised by df.take() instead of iloc.

Written with AI assistance. Measured on 2026-10-23 in the python:3-alpine Docker image (Python 3.14) with pandas 2.3.3 and pandas 3.1.0. Each block was run verbatim on both versions; the outputs were identical and are pasted unedited. PlainHeaders is our extension; Python and pandas are free.