IndexError: list index out of range
1 · The lesson
readWhat this error means
You asked Python for an item at a position that doesn't exist in the list. Lists in Python are zero-indexed: a list of length 3 has valid indices 0, 1, 2. Asking for index 3 (or -4) raises IndexError.
When you see it
>>> nums = [10, 20, 30] >>> nums[5] Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list index out of range
Why it happens
The most frequent causes are off-by-one errors in loops, assumptions about input size that don't hold at runtime (empty list, short list), and confusing length with maximum index. Remember: for a list of length n, the last valid index is n - 1.
How to fix it
1. Validate the index before access:
i = 5 if i < len(nums): value = nums[i] else: value = None
setup added so this can run · defines nums
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) nums = _AutoMock('nums')
2. Iterate the list directly instead of by index (the Pythonic fix):
for n in nums: print(n)
setup added so this can run · defines nums
nums = ["alpha", "beta", "gamma"]
If you need the index too, use enumerate:
for i, n in enumerate(nums): print(i, n)
setup added so this can run · defines nums
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) nums = _AutoMock('nums')
3. Catch the error when the bounds are genuinely uncertain:
try: head = parts[3] except IndexError: head = ""
setup added so this can run · defines parts
parts = ["alpha", "beta", "gamma"]
4. Use slicing — slicing never raises IndexError:
first_five = nums[:5] # returns [10, 20, 30] safely
setup added so this can run · defines nums
nums = ["alpha", "beta", "gamma"]
When you'd actually see this in real code
- A classic off-by-one:
for i in range(len(nums) + 1): nums[i]— the+ 1walks one past the end. Userange(len(nums))or just iterate directly. - Splitting a CSV row and assuming five columns:
row = line.split(",")thenrow[4]breaks on a malformed line with four commas missing or an empty trailing line in the file. - Popping from a list in a loop without checking emptiness:
while True: x = stack.pop()should bewhile stack: x = stack.pop().
Related errors
- IndexError: string index out of range
- KeyError in Python: how to fix it
- ValueError: not enough values to unpack
See Also
- All Python errors — the full index, by type and by when it happens.
- List cheat sheet
- Loops and iteration tutorial
Practice this
on practicepython.inShort exercises that run in your browser and tell you what your code actually did, not just whether a test passed.