IndexError: tuple index out of range means you asked for a position the tuple doesn’t have. A tuple of length n has indexes 0 to n - 1 only. Fix it by checking len() first, looping without indexes, or handling empty tuples:
store = ("Austin", "TX", 78701)
store[3] # IndexError: valid indexes are 0, 1, 2
The tracebacks here are copied from Python 3.12.5, so the arrows under the failing index match what you’ll see.
You’ll see the error itself, off-by-one loops, empty tuples from database queries, *args with too few values, and five fixes, from a length check to star unpacking.
What causes IndexError: tuple index out of range?
Indexes start at 0, so the last valid index is one less than the length. Negative indexes count from the end, down to -len(t):
store = ("Austin", "TX", 78701)
print(store[0], store[2], store[-1], store[-3])
print(store[3])
Output:
Austin 78701 78701 Austin
Traceback (most recent call last):
File "C:\pyguides\tuple_index.py", line 3, in <module>
print(store[3])
~~~~~^^^
IndexError: tuple index out of range

Python 3.11+ underlines the exact index that failed. The same rule applies to lists and strings, as explained in fixing IndexError: list index out of range.
Fix off-by-one loops over a tuple
range(len(t) + 1) or <= instead of < goes one step too far. Usually you don’t need the index at all:
prices = (19.99, 5.25, 102.00)
total = 0.0
try:
for i in range(len(prices) + 1): # one step too far
total += prices[i]
except IndexError as err:
print(f"failed at i={i}: {err}")
total = sum(prices) # no index needed at all
print(f"total: ${total:.2f}")
for i, price in enumerate(prices, start=1):
print(f"item {i}: ${price:.2f}")
Output:
failed at i=3: tuple index out of range
total: $127.24
item 1: $19.99
item 2: $5.25
item 3: $102.00

enumerate() gives you a counter and the item together. Other looping patterns are in iterating through tuples in Python.
Why does indexing a function’s result raise this error?
Functions that return search results often return an empty tuple when nothing matches. Indexing [0] on that fails, as with this database lookup:
import sqlite3
db = sqlite3.connect(":memory:")
db.execute("CREATE TABLE customers (id INTEGER, name TEXT, state TEXT)")
db.executemany("INSERT INTO customers VALUES (?, ?, ?)", [(1, "Emily Carter", "TX"), (2, "James Wilson", "CO")])
def find_by_state(state):
return tuple(db.execute("SELECT name FROM customers WHERE state = ?", (state,)))
print(find_by_state("TX"))
print(find_by_state("FL")) # no match -> empty tuple
try:
first = find_by_state("FL")[0]
except IndexError as err:
print("IndexError:", err)
rows = find_by_state("FL")
first = rows[0][0] if rows else "no customer in FL"
print(first)
Output:
(('Emily Carter',),)
()
IndexError: tuple index out of range
no customer in FL

if rows is False for an empty tuple, so test before you index. More empty checks are in checking if a tuple is empty in Python.
Fix IndexError when using *args
*args collects positional arguments into a tuple, so a caller passing too few values triggers the same error inside your function:
def ship(*args):
print(f"got {len(args)} argument(s): {args}")
return f"ship to {args[0]}, {args[1]}"
print(ship("Denver", "CO"))
try:
ship("Denver")
except IndexError as err:
print("IndexError:", err)
def ship_fixed(city: str, state: str = "TX") -> str: # named parameters fail clearly
return f"ship to {city}, {state}"
print(ship_fixed("Denver"))
Output:
got 2 argument(s): ('Denver', 'CO')
ship to Denver, CO
got 1 argument(s): ('Denver',)
IndexError: tuple index out of range
ship to Denver, TX
Named parameters with defaults fail with a clearer message, or not at all. Passing tuples into functions is covered in passing a tuple as an argument to a function.
Five ways to avoid tuple index out of range
Pick the fix that matches what a missing item means in your code:
def get(t: tuple, i: int, default=None):
"""t[i], or default when i is out of range."""
return t[i] if -len(t) <= i < len(t) else default
store = ("Austin", "TX", 78701)
print(get(store, 1), get(store, 5), get(store, 5, "n/a"), get((), 0, "empty"))
city, *rest = store # star unpacking never raises for extra items
print(city, rest)
first, *others = ("Reno",)
print(first, others)
try:
zip_code = store[3]
except IndexError:
zip_code = "unknown"
print("zip:", zip_code)
Output:
TX None n/a empty
Austin ['TX', 78701]
Reno []
zip: unknown

Star unpacking is my favorite when I only need the first item. More unpacking tricks are in unpacking a tuple in Python.
Tuple index fixes compared
| Situation | Fix |
|---|---|
| Looping over items | for item in t or enumerate(t) |
| Result may be empty | if t: t[0] |
| Optional position | t[i] if -len(t) <= i < len(t) else default |
| Only need the first item | first, *rest = t |
| Missing item is rare | try: ... except IndexError: |
| Variable-length *args | Named parameters with defaults |
Other error guides on the site you might need:
- Fix IndexError: string index out of range
- Fix TypeError: ‘tuple’ object is not callable
- Fix a Python dictionary KeyError
- Find the length of a tuple in Python
Frequently asked questions
What does tuple index out of range mean?
You used an index that’s greater than or equal to the tuple’s length, or below -len(t).
What is the last valid index of a tuple?
len(t) - 1, or simply -1.
Why do I get this error on [0]?
The tuple is empty, often because a function or query found nothing. Check if t: first.
How do I get a tuple item with a default?
Use t[i] if -len(t) <= i < len(t) else default, or wrap the access in try/except IndexError.
Is this error different from list index out of range?
It’s the same IndexError; only the message names the type.
Where is IndexError documented?
See IndexError in the Python docs.

Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn