Python IndexError: list index out of range
IndexError: list index out of range
Verified against CPython 3.13 source (Objects/listobject.c), Python docs: built-in-exceptions, Python docs: tutorial/datastructures · Updated April 2026
> quick_fix
You accessed a list, tuple, or string at an index that doesn't exist. Either the index is too large (>= len(seq)), too negative (< -len(seq)), or the sequence is empty. Check len() before indexing, or use try-except IndexError if missing-index is a normal case.
# Raises IndexError if list is empty or shorter than expected
first = items[0]
# Fix - check first
if items:
first = items[0]
else:
first = None
# Or use slicing (returns empty, not error)
first = items[:1]
# Or use a default
first = next(iter(items), None)What causes this error
Python's sequence types raise IndexError when you ask for a position that isn't there. Lists are 0-indexed, so the last valid index is len(list) - 1. Negative indices count from the end, so -1 is the last item. Anything outside [-len, len-1] raises IndexError immediately - Python does not silently return None or extend the list.
How to fix it
- 01
step 1
Print the length of the sequence and the index you're using
Add a print(len(items), i) above the failing line. The mismatch is usually obvious.
- 02
step 2
Check for off-by-one errors
for i in range(len(items)): items[i] is fine. But for i in range(len(items) + 1): items[i] is off by one.
- 03
step 3
Use slicing for safe access
items[100:101] returns [] if items has fewer than 100 elements - never raises. Same for items[-100:-99]. Slicing is forgiving where indexing is not.
- 04
step 4
For dictionaries, use .get() with default
But if you're seeing IndexError on a dict, you're probably indexing a value that should be a list. Re-read the error message and verify the type of the variable.
- 05
step 5
Wrap in try-except IndexError when missing-index is expected
Common in 'pop until empty' loops or input parsing. But for normal access, prefer the explicit length check.
try: first = items[0] except IndexError: first = None
How to verify the fix
- The IndexError no longer fires.
- Empty-sequence case handled (returns sensible default).
- Loop bounds match len(seq) exactly.
Why IndexError happens at the runtime level
Python's list, tuple, and string types implement the sq_item slot in their PySequenceMethods table. When you access seq[i], the interpreter calls PySequence_GetItem which invokes the type's sq_item with the normalised index. The implementation in Objects/listobject.c (list_item) compares the index against ob_size (the list's length); if i >= size or i < -size, it raises PyExc_IndexError immediately with a fixed 'list index out of range' message. The check is unconditional and there's no auto-extension - Python's design treats out-of-bounds access as a programmer error, not a runtime fallback.
Common debug mistakes for IndexError
- Looping while True and incrementing an index instead of using for-each - the index passes the end and IndexError fires; for item in items handles bounds automatically.
- Using items[-1] on a possibly-empty list expecting None - empty lists have no last item and raise IndexError just like positive overflow.
- Calling sys.argv[1] without checking len(sys.argv) - if the user runs the script with no arguments, IndexError fires immediately and the message is unhelpful for end-users.
- Splitting a string by a delimiter and indexing parts[1] without confirming the delimiter was present - 'foo'.split(':') returns ['foo'] and [1] raises.
- Modifying a list during iteration with items.pop() and continuing the loop - the index becomes stale and IndexError fires before the loop's natural end.
When IndexError signals a deeper problem
IndexError that returns under load usually signals an off-by-one in a hot path that worked on test fixtures but fails on real input. The architectural cause is direct indexing into structures that should be iterated or destructured. Replace items[0], items[1], items[2] = a, b, c with explicit unpacking (a, b, c = items, with a length assertion or itertools fill) and the IndexError converts into a clearer ValueError at the unpack boundary. For nested data, use safe-navigation libraries (operator.itemgetter, jmespath, get with default). Without a typed boundary, the IndexError will keep returning every time the upstream data shape changes.
Frequently asked questions
What's the difference between IndexError and KeyError?
IndexError - integer index missing on a sequence (list, tuple, string). KeyError - hashable key missing on a mapping (dict, set). Different exception types, same idea.
Why doesn't Python auto-extend a list when I assign past the end?
By design - it would mask off-by-one bugs and make code unpredictable. To grow a list, use append() or extend().
Can a string raise IndexError?
Yes. Strings are sequences, so 'abc'[5] raises IndexError. Same rules as lists.