# How to Fix Python IndexError: list index out of range
The IndexError occurs when you try to access an element at a position that does not exist in a list, tuple, or other sequence. This typically happens when accessing the wrong index or when the sequence is shorter than expected.
Error Patterns
Basic IndexError
Traceback (most recent call last):
File "app.py", line 3, in <module>
item = items[5]
IndexError: list index out of rangeEmpty List Access
Traceback (most recent call last):
File "app.py", line 2, in <module>
first = items[0]
IndexError: list index out of rangeString IndexError
Traceback (most recent call last):
File "app.py", line 4, in <module>
char = text[100]
IndexError: string index out of rangeTuple IndexError
Traceback (most recent call last):
File "app.py", line 3, in <module>
value = coordinates[3]
IndexError: tuple index out of rangeCommon Causes
- 1.Empty list - Accessing index from empty sequence
- 2.Off-by-one errors - Using
len(items)instead oflen(items) - 1 - 3.Dynamic list changes - List was modified, now shorter
- 4.Wrong assumptions - Expecting list to have certain length
- 5.Loop index errors - Loop iterating beyond list bounds
- 6.Conditional access - Accessing index without checking length
Diagnosis Steps
Step 1: Check List Length
```python # Always check length before accessing items = get_items() print(f"List length: {len(items)}") print(f"List contents: {items}")
# Then access safely if len(items) > 5: print(items[5]) ```
Step 2: Check Index Value
```python # Verify the index you're trying to access index = 10 items = [1, 2, 3, 4, 5]
print(f"Attempting to access index {index}") print(f"Valid indices: 0 to {len(items) - 1}")
if 0 <= index < len(items): print(items[index]) else: print(f"Index {index} is out of bounds") ```
Step 3: Find Where List Is Modified
```python # Trace where the list gets modified def trace_list_modifications(items): original_len = len(items) print(f"Initial length: {original_len}")
# Process items, print length after each modification # Watch for: pop(), remove(), clear(), del, assignment return items ```
Solutions
Solution 1: Check Length Before Access
```python # Problem: Accessing without checking items = [] first = items[0] # IndexError on empty list
# Fix: Check length items = [] if len(items) > 0: first = items[0] else: first = None # Or handle empty case
# Fix: Use conditional expression first = items[0] if items else None ```
Solution 2: Handle Off-by-One Errors
```python # Problem: Last element access items = [1, 2, 3, 4, 5] last = items[5] # IndexError: index 5 doesn't exist (0-4 are valid)
# Fix: Use len() - 1 for last element last = items[len(items) - 1] # items[4] = 5
# Better: Use negative indexing last = items[-1] # Last element second_last = items[-2] # Second to last
# Safely with negative index check if len(items) > 0: last = items[-1] ```
Solution 3: Use try/except for Safe Access
```python # Fix: Wrap access in try/except items = [1, 2, 3]
try: value = items[10] except IndexError: value = None # Handle missing element print("Index out of range, using default")
# For function returning list element def safe_get(items, index, default=None): try: return items[index] except IndexError: return default
value = safe_get(items, 10, "default") ```
Solution 4: Use Slice Instead of Index
```python # Problem: Single element access items = [1, 2, 3] item = items[5] # IndexError
# Fix: Use slice (returns empty list if out of range) item = items[5:6] # Returns [] instead of raising IndexError if item: result = item[0] else: result = None
# Get first element safely first = items[:1] # [] if empty, [first] otherwise if first: print(first[0]) ```
Solution 5: Iterate Safely
```python # Problem: Manual index iteration items = [1, 2, 3] for i in range(len(items) + 1): # Wrong: +1 causes IndexError print(items[i])
# Fix: Iterate directly over items for item in items: print(item) # No IndexError possible
# Fix: Use enumerate if you need index for i, item in enumerate(items): print(f"Index {i}: {item}")
# Fix: Check bounds in manual iteration for i in range(len(items)): # Correct range print(items[i]) ```
Solution 6: Handle Split Results
```python # Problem: Split might not return expected parts text = "hello" parts = text.split(":") first = parts[1] # IndexError: parts has only 1 element
# Fix: Check parts length text = "hello" parts = text.split(":") if len(parts) > 1: first = parts[1] else: first = ""
# Fix: Use maxsplit and defaults text = "hello" first, second = text.split(":", 1) if ":" in text else (text, "") ```
Solution 7: Handle CSV Row Access
```python import csv
# Problem: Rows might have different column counts with open("data.csv") as f: reader = csv.reader(f) for row in reader: email = row[3] # IndexError if row has fewer columns
# Fix: Check row length with open("data.csv") as f: reader = csv.reader(f) for row in reader: email = row[3] if len(row) > 3 else ""
# Fix: Use helper function def get_column(row, index, default=""): return row[index] if len(row) > index else default
email = get_column(row, 3) ```
Solution 8: Handle API Response Arrays
```python import requests
response = requests.get("https://api.example.com/items") items = response.json()
# Problem: Expecting certain structure first_item = items[0] # IndexError if empty response
# Fix: Validate response structure if items and isinstance(items, list): first_item = items[0] if len(items) > 0 else None else: first_item = None print("Unexpected response format") ```
Safe Access Patterns
Safe First/Last Access
```python def safe_first(items, default=None): """Get first element safely.""" return items[0] if items else default
def safe_last(items, default=None): """Get last element safely.""" return items[-1] if items else default
def safe_get(items, index, default=None): """Get element at index safely.""" try: return items[index] except (IndexError, TypeError): return default
# Usage items = [1, 2, 3] print(safe_first(items)) # 1 print(safe_last(items)) # 3 print(safe_get(items, 10)) # None print(safe_first([])) # None ```
Slice Patterns
```python # Slices never raise IndexError items = [1, 2, 3]
# Get first N elements safely first_three = items[:3] # [1, 2, 3] first_five = items[:5] # [1, 2, 3] - returns all available
# Get last N elements safely last_three = items[-3:] # [1, 2, 3] last_five = items[-5:] # [1, 2, 3] - returns all available
# Middle elements middle = items[1:2] # [2] ```
Negative Index Handling
```python # Negative indices work from end items = [1, 2, 3, 4, 5] print(items[-1]) # 5 (last) print(items[-2]) # 4 (second last) print(items[-6]) # IndexError (too negative)
# Safe negative index def safe_negative(items, neg_index, default=None): if len(items) >= abs(neg_index): return items[neg_index] return default
value = safe_negative(items, -10) # None instead of IndexError ```
Common IndexError Patterns
Parsing Fixed Format Data
```python def parse_log_line(line): """Parse log line safely.""" parts = line.split()
# Use safe access for each field timestamp = parts[0] if len(parts) > 0 else "" level = parts[1] if len(parts) > 1 else "INFO" message = " ".join(parts[2:]) if len(parts) > 2 else ""
return { "timestamp": timestamp, "level": level, "message": message } ```
Processing Command Arguments
```python import sys
def get_arg(index, default=None): """Get command line argument safely.""" return sys.argv[index] if len(sys.argv) > index else default
# Usage filename = get_arg(1, "default.txt") mode = get_arg(2, "read") ```
Matrix/2D Array Access
```python matrix = [[1, 2, 3], [4, 5]]
# Problem: Inconsistent row lengths value = matrix[0][5] # IndexError value = matrix[2][0] # IndexError
# Fix: Check both dimensions def safe_matrix_get(matrix, row, col, default=None): try: return matrix[row][col] except IndexError: return default
value = safe_matrix_get(matrix, 0, 5, 0) ```
Prevention Tips
- 1.Check length before access -
if len(items) > index - 2.Use slice syntax - Returns empty instead of raising error
- 3.Iterate directly - Don't use
range(len(items))unless necessary - 4.Validate input - Check data structure assumptions
- 5.Use helper functions - Centralize safe access patterns
```python # Good pattern: Defensive list handling def process_items(items): if not items: # Handle empty return []
# Safe access patterns throughout first = items[0] if items else None rest = items[1:] # Safe slice
return process(first, rest) ```
Related Errors
KeyError- Dictionary key not foundTypeError- Object doesn't support indexingValueError- Wrong value type for operationAttributeError- Object doesn't have the attribute