IndexError appears when a sequence index falls outside the valid range for the object you are reading. Lists, tuples, strings, and similar sequences all enforce their own bounds at runtime.
The explanation should show how Python numbers positions from zero, why negative indexes still have limits, and why slices behave differently from single-item access.
This topic becomes clear when you compare direct index access, looping by index, and safer alternatives such as enumerate or a length check before the read.
An IndexError occurs in Python when you try to access an element of a sequence (list, tuple, or string) using an index that is outside the valid range. Python sequences are zero-indexed, meaning the first element is at index 0 and the last is at index len(sequence) - 1. Accessing any index beyond this range raises an IndexError.
# Out-of-range index: valid positions are 0, 1, and 2
items = [10, 20, 30]
print(items[3]) # IndexError: list index out of range (valid: 0, 1, 2)
# Valid reads: use the last real index or a negative index
print(items[2]) # 30 - last valid index
print(items[-1]) # 30 - negative index for last element
Trying to access any index of an empty list raises an IndexError immediately. Always check if a list is non-empty before accessing its elements.
A classic off-by-one error occurs when using range(len(list)) but accidentally going one step too far, or when manually incrementing an index counter past the last valid position.
Using a hardcoded index assumes the list always has a certain number of elements. If the list is shorter than expected (e.g., from a filtered result or API response), the index will be out of range.
When using a while loop with a manual index, it is easy to forget to stop at the right boundary. Always use while i < len(list) rather than while i
results = []
first = results[0] # IndexError: list index out of range
results = []
# Check before accessing
if results:
first = results[0]
else:
first = None
# Or use a try/except
try:
first = results[0]
except IndexError:
first = None
fruits = ["apple", "banana", "cherry"]
for i in range(len(fruits) + 1): # +1 causes IndexError on last iteration
print(fruits[i])
fruits = ["apple", "banana", "cherry"]
# Best: iterate directly over the list
for fruit in fruits:
print(fruit)
# If you need the index, use enumerate()
for i, fruit in enumerate(fruits):
print(f"{i}: {fruit}")
def get_top_scores(scores):
return scores[0], scores[1], scores[2] # IndexError if fewer than 3 scores
scores = [95, 87]
top = get_top_scores(scores) # IndexError: list index out of range
def get_top_scores(scores, n=3):
# Use slicing - never raises IndexError
return scores[:n]
scores = [95, 87]
top = get_top_scores(scores) # [95, 87] - no error
items = [1, 2, 3]
i = 0
while i <= len(items): # Should be < not <=
print(items[i]) # IndexError on last iteration when i == 3
i += 1
items = [1, 2, 3]
i = 0
while i < len(items): # Strict less-than
print(items[i])
i += 1
# Even better: use a for loop
for item in items:
print(item)
It means you tried to access an index that does not exist in the list. For a list of 3 elements, valid indices are 0, 1, and 2. Accessing index 3 or higher raises this error.
Use negative indexing: list[-1] returns the last element. But first check the list is not empty: if my_list: last = my_list[-1].
IndexError occurs with sequences (lists, tuples, strings) when an integer index is out of range. KeyError occurs with dictionaries when a key does not exist.
Explore 500+ free tutorials across 20+ languages and frameworks.