Pandas iloc IndexError: Positional Out of Bounds (2026)

You called df.iloc[100] but the DataFrame has only 50 rows, so pandas threw IndexError: single positional indexer is out-of-bounds. Note: .iloc raises IndexError (position-based), while .loc raises KeyError (label-based). Knowing which is which saves debugging time.

Pandas iloc IndexError Positional Out of Bounds (2026)
Pandas iloc IndexError Positional Out of Bounds (2026)

📌 Quick answer: Guard with if len(df) > i: row = df.iloc[i]. For “last N rows” use df.tail(N). For “first N rows” use df.head(N). Both are safe on any size DataFrame, including empty ones.

Cause 1: Hardcoded position larger than DataFrame

You wrote df.iloc[100] in production code; user uploaded a 50-row CSV; crash.

df = pd.read_csv("upload.csv")
row = df.iloc[100]    # ❌ IndexError if df has 50 rows

# Safe
if len(df) > 100:
    row = df.iloc[100]
else:
    row = None

Cause 2: Empty DataFrame after filter

Filter returned zero rows, df.iloc[0] now fails.

high = df[df["score"] > 100]
first = high.iloc[0]    # ❌ if no row has score > 100

# Safe
if not high.empty:
    first = high.iloc[0]

Cause 3: Negative index too negative

df.iloc[-100] on a 50-row DataFrame fails.

df.iloc[-1]    # ✓ last row
df.iloc[-50]   # ✓ first row (wraps)
df.iloc[-51]   # ❌ IndexError

Cause 4: iloc slice off the end (does NOT error)

df.iloc[10:20] on a 5-row DataFrame returns empty, NOT an error. Surprising if you expected an error.

small = pd.DataFrame({"a": [1, 2, 3]})
small.iloc[10:20]    # ✓ returns empty DataFrame, no error
small.iloc[10]       # ❌ raises IndexError

# Slice semantics differ from scalar semantics in pandas

Cause 5: iloc with negative slice and ambiguity

df.iloc[-3:0] returns empty (because -3 > 0 in slice terms, even though -3 means “row count minus 3” in normal indexing).

df.iloc[-3:]      # ✓ last 3 rows
df.iloc[-3:0]     # ⚠ empty (slice stop=0 means before first row)
df.iloc[:-3]      # ✓ everything except last 3

Prevention

  1. Use .head(N) and .tail(N) for safe top/bottom access
  2. Always check not df.empty or len(df) > i before scalar iloc
  3. Prefer slices over scalars: df.iloc[0:1] returns empty on empty df instead of erroring
  4. Don’t mix .iloc with .loc semantics: .iloc is position, .loc is label

Frequently Asked Questions

What’s the difference between iloc IndexError and loc KeyError?

iloc is position-based and raises IndexError when the position is out of range. loc is label-based and raises KeyError when the label doesn’t exist. Same DataFrame, different exception types depending on which accessor.

Why does df.iloc[100] error but df.iloc[10:20] doesn’t?

Scalar vs slice semantics. Scalar iloc raises IndexError when out of bounds. Slice iloc silently clips to the available range and returns whatever’s there (often empty). This is consistent with Python list slicing.

How do I safely access the first or last row of a DataFrame?

df.head(1) for first row (returns empty DataFrame if empty). df.tail(1) for last row. df.iloc[0] only if you’ve already verified df is non-empty.

Can negative iloc indexes go too negative?

Yes. df.iloc[-N] works for N up to len(df). df.iloc[-len(df)-1] raises IndexError. df.iloc[-N:] (slice form) clips safely and returns the last N rows or as many as exist.

Should I use iloc or loc?

iloc when you want ‘the Nth row by position regardless of label’. loc when you want ‘the row with this specific index label’. iloc is safer in pipelines because position doesn’t depend on the index being intact.

Leave a Comment