Fix: Python IndexError: list index out of range
Quick Answer
How to fix Python IndexError list index out of range caused by empty lists, off-by-one errors, wrong loop bounds, deleted elements, and negative indexing mistakes.
The Error
You run a Python script and get:
Traceback (most recent call last):
File "app.py", line 4, in <module>
print(items[5])
IndexError: list index out of rangeOr variations:
IndexError: string index out of rangeIndexError: tuple index out of rangeYou tried to access an element at an index that does not exist. The list (or string, or tuple) does not have that many elements.
Why This Happens
Python sequences are zero-indexed. A list with 5 elements has valid indices 0 through 4. Accessing index 5 is out of range:
items = ["a", "b", "c", "d", "e"] # len = 5
items[0] # "a" — first element
items[4] # "e" — last element
items[5] # IndexError — no 6th elementCommon causes:
- Empty list. The list has no elements, so any index fails.
- Off-by-one error. Using
len(items)as an index instead oflen(items) - 1. - Loop modifying the list. Removing elements while iterating changes the list length.
- Hardcoded index. Assuming data always has a certain number of elements.
- API response with fewer items than expected. The response returned 2 items but you access
response[3].
Fix 1: Check the List Length First
Before accessing an index, verify the list has enough elements:
items = get_results()
if len(items) > 0:
first = items[0]
else:
first = NoneFor a specific index:
if len(items) > 3:
fourth = items[3]Using a helper function:
def safe_get(lst, index, default=None):
return lst[index] if -len(lst) <= index < len(lst) else default
items = [10, 20, 30]
safe_get(items, 5) # None
safe_get(items, 5, 0) # 0
safe_get(items, 1) # 20Pro Tip: For dictionaries, use
.get()with a default value. Lists do not have.get(), so you need the length check or try/except. If you frequently need safe list access, consider a helper function or usingnext(iter(items), default)for the first element.
Fix 2: Fix Off-By-One Errors
The most common logic error. Lists are zero-indexed, so the last valid index is len(items) - 1:
Broken:
items = [10, 20, 30]
# Wrong — index 3 does not exist
for i in range(len(items) + 1):
print(items[i]) # IndexError when i = 3Fixed:
for i in range(len(items)):
print(items[i])Better — iterate directly:
for item in items:
print(item)Access the last element safely:
items = [10, 20, 30]
last = items[-1] # 30 — negative indexing
last = items[len(items) - 1] # 30 — manual (avoid this)Negative indices count from the end: -1 is the last element, -2 is second to last. But items[-1] still raises IndexError on an empty list.
Fix 3: Handle Empty Lists
Empty lists cause IndexError on any index access:
results = []
first = results[0] # IndexError: list index out of rangeFix with a guard:
results = get_search_results(query)
if results:
first = results[0]
print(f"Top result: {first}")
else:
print("No results found")Fix with a default value:
first = results[0] if results else "No results"Fix with try/except:
try:
first = results[0]
except IndexError:
first = NoneThe if results: check is cleanest for most cases. Use try/except when the empty case is genuinely exceptional.
Fix 4: Fix Loops That Modify Lists
Removing elements while iterating over a list changes the indices:
Broken:
items = [1, 2, 3, 4, 5]
for i in range(len(items)):
if items[i] % 2 == 0:
items.pop(i) # List shrinks, but range doesn't
# IndexError: list index out of rangeWhen you pop index 1 (value 2), the list becomes [1, 3, 4, 5]. Now index 3 is 5, and index 4 does not exist.
Fixed — iterate over a copy:
items = [1, 2, 3, 4, 5]
items = [x for x in items if x % 2 != 0]
# [1, 3, 5]Fixed — iterate in reverse:
items = [1, 2, 3, 4, 5]
for i in range(len(items) - 1, -1, -1):
if items[i] % 2 == 0:
items.pop(i)Iterating in reverse is safe because popping later indices does not affect earlier ones.
Fixed — filter:
items = list(filter(lambda x: x % 2 != 0, items))Common Mistake: Using
for item in items: items.remove(item)to remove elements. This skips elements becauseremove()shifts the remaining elements and the loop’s internal pointer advances past the next item. Always use list comprehension or reverse iteration.
Fix 5: Fix String Indexing
Strings are sequences too, and the same rules apply:
name = "Alice"
name[0] # "A"
name[4] # "e"
name[5] # IndexError: string index out of rangeCommon case — split with fewer parts than expected:
line = "Alice"
parts = line.split(",") # ["Alice"] — only 1 part
name = parts[0] # "Alice"
email = parts[1] # IndexError!Fixed:
parts = line.split(",")
name = parts[0] if len(parts) > 0 else ""
email = parts[1] if len(parts) > 1 else ""Or with unpacking and defaults:
parts = line.split(",")
name, *rest = parts
email = rest[0] if rest else ""If your string parsing involves JSON, see Fix: JSON parse unexpected token for format issues.
Fix 6: Fix Pandas and NumPy Indexing
Pandas DataFrames and NumPy arrays can also raise IndexError:
Pandas — iloc out of range:
import pandas as pd
df = pd.DataFrame({"name": ["Alice", "Bob"]})
df.iloc[5] # IndexError: single positional indexer is out-of-boundsFixed:
if len(df) > 5:
row = df.iloc[5]NumPy:
import numpy as np
arr = np.array([1, 2, 3])
arr[5] # IndexError: index 5 is out of bounds for axis 0 with size 3Fix: Check shape before accessing:
if arr.shape[0] > 5:
value = arr[5]Fix 7: Fix Multithreaded List Access
Multiple threads accessing the same list can cause IndexError if one thread removes elements while another accesses them:
import threading
shared_list = [1, 2, 3, 4, 5]
def worker():
while shared_list:
item = shared_list.pop(0) # Race condition!
process(item)Fixed — use a thread-safe queue:
from queue import Queue
q = Queue()
for item in [1, 2, 3, 4, 5]:
q.put(item)
def worker():
while not q.empty():
item = q.get()
process(item)
q.task_done()Or use a lock:
lock = threading.Lock()
def worker():
with lock:
if shared_list:
item = shared_list.pop(0)
process(item)Fix 8: Debug the Index Error
When the error is not obvious, add debugging:
items = get_data()
index = calculate_index()
print(f"List length: {len(items)}")
print(f"Attempting index: {index}")
print(f"List contents: {items}")
value = items[index]Use enumerate for safe indexed access:
for i, item in enumerate(items):
print(f"Index {i}: {item}")This never raises IndexError because enumerate only yields valid indices.
Still Not Working?
If you have checked all the fixes above:
Check for nested lists. items[0][1] fails if items[0] has fewer than 2 elements, even if items has many elements.
Check for generators vs lists. Generators cannot be indexed:
gen = (x for x in range(10))
gen[0] # TypeError: 'generator' object is not subscriptableConvert to list first: list(gen)[0].
Check for deque maxlen. A collections.deque with maxlen automatically removes old elements, which might make expected indices invalid.
Check for custom __getitem__. If the object is a custom class, its __getitem__ method might raise IndexError for unexpected reasons.
If the error is about dictionary keys rather than list indices, see Fix: Python KeyError. If the value is None and you are trying to subscript it, see Fix: TypeError: ‘NoneType’ object is not subscriptable.
For similar issues with missing attributes on None values, see Fix: AttributeError: ‘NoneType’ has no attribute.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: AWS Lambda Unable to import module / Runtime.ImportModuleError
How to fix the AWS Lambda Runtime.ImportModuleError and Unable to import module error caused by wrong handler paths, missing dependencies, layer issues, and packaging problems.
Fix: Python TypeError: unhashable type: 'list'
Learn why Python raises TypeError unhashable type list, dict, or set and how to fix it when using dictionary keys, sets, groupby, dataclasses, and custom classes.
Fix: Django Forbidden (403) CSRF verification failed
How to fix Django 403 CSRF verification failed error caused by missing CSRF tokens, AJAX requests, cross-origin issues, HTTPS misconfig, and session problems.
Fix: FastAPI 422 Unprocessable Entity (validation error)
How to fix FastAPI 422 Unprocessable Entity error caused by wrong request body format, missing fields, type mismatches, query parameter errors, and Pydantic validation.