IndexError: list index out of range (tested)
IndexError: list index out of range means you asked a sequence (list, tuple, or string) for a position that doesn't exist — the index is too large, or the sequence is shorter (often empty) than your code assumed. Unlike KeyError, which is about missing dict keys, this is purely about numeric position versus length. We reproduced nine real causes on a live interpreter.
1. The rule behind every case below
A sequence of length n has valid indices 0 to n-1 (and -1 to -n from the end). Any index outside that range raises IndexError, with no rounding, clamping, or silent None — Python never guesses which element you meant.
2. Nine reproduced cases
| Code | Exact error (Python 3.13.5) |
|---|---|
l = [1,2,3]; l[5] | IndexError: list index out of range |
l[-5] | IndexError: list index out of range |
l[3] = 99 (assignment) | IndexError: list assignment index out of range |
l.pop(5) | IndexError: pop index out of range |
for i in range(len(l)+1): l[i] | IndexError: list index out of range |
"abc"[10] | IndexError: string index out of range |
(1,2)[5] | IndexError: tuple index out of range |
[][0] (empty list) | IndexError: list index out of range |
sys.argv[1] (no CLI arg given) | IndexError: list index out of range |
The message changes slightly by operation (pop index, assignment index) and by container type (list/tuple/string), but the structure is always "<thing> index out of range."
3. Cause 1: a plain off-by-one
The classic mistake — looping one index too far, usually from using len(l) where len(l) - 1 was meant, or <= instead of <:
>>> l = [1, 2, 3]
>>> for i in range(len(l) + 1):
... l[i]
IndexError: list index out of range
Fix: loop with for i in range(len(l)):, or better, avoid indices entirely with for item in l: when you don't actually need the position.
4. Cause 2: the sequence is empty
This is the single most common real-world cause: code assumes a list has at least one item (a search result, a query result, a split string) when it can legitimately be empty.
>>> results = []
>>> results[0]
IndexError: list index out of range
Fix: check if results: before indexing, or use results[0] if results else default.
5. Cause 3: negative indices past the start
Negative indices count from the end (-1 is the last element), but they run out just as fast as positive ones:
>>> l = [1, 2, 3]
>>> l[-5]
IndexError: list index out of range
Fix: same as any other out-of-range index — check the length, or use l[-5:] (slicing) instead of l[-5] (indexing) if you want "up to 5 from the end, or everything if shorter" behavior. Slicing never raises IndexError; indexing always can.
6. Cause 4: command-line arguments (sys.argv)
A very common script-writing bug: assuming the user passed an argument.
>>> import sys
>>> sys.argv[1] # run with no arguments
IndexError: list index out of range
Fix: check len(sys.argv) > 1 first, or use the argparse module, which reports a proper usage error instead of a raw traceback.
7. Cause 5: mutating methods have their own messages
pop(index) and index assignment (l[i] = x) both raise IndexError too, but with slightly different wording than a plain read, which is useful for telling from a traceback alone which operation failed:
>>> l.pop(5)
IndexError: pop index out of range
>>> l[3] = 99
IndexError: list assignment index out of range
Note that l.append(x) never raises this — it always adds at the end regardless of length, so switching from index assignment to append is a common fix when you don't actually need a specific position.
8. IndexError vs KeyError vs TypeError
IndexError is for sequences (list, tuple, str) indexed by position. KeyError is for mappings (dict) indexed by key. If you index a sequence with something that isn't an integer at all (l["a"]), you get a third, different error: TypeError: list indices must be integers or slices, not str — worth distinguishing because the fix is different (wrong container type, not wrong position).
9. Fix checklist
- Check length before indexing by position:
if i < len(l):orif l:for the "any elements?" case. - Prefer iterating (
for item in l) orenumerate(l)over manual index loops when you don't need to jump to specific positions. - Use slicing (
l[a:b]) instead of indexing when "give me up to N items, or fewer if not enough" is really what you want — slicing never raises. - For CLI scripts, validate
sys.argvlength or switch toargparse. - Use
l.pop()(no argument, removes the last item) instead ofl.pop(-1)when you just want "the last one, if any" — guard the empty case separately either way.
If the error instead says 'NoneType' object has no attribute, you're indexing or calling a method on a missing value rather than an out-of-range position — see AttributeError: 'NoneType' object has no attribute.
Frequently asked questions
What does IndexError: list index out of range mean?
It means code tried to access a list (or tuple/string) position that doesn't exist, using l[i] where i is less than 0 - len(l) or greater than len(l) - 1. A length-3 list only has valid indices 0, 1, 2 (or -1, -2, -3 from the end).
What is the difference between IndexError and KeyError?
IndexError is raised by sequences (list, tuple, str) accessed by numeric position. KeyError is raised by mappings (dict) accessed by key. They are different exception types for different container kinds and are not interchangeable.
Why does my loop raise IndexError on the last iteration?
Almost always an off-by-one: using range(len(l) + 1) or <= len(l) - 1 incorrectly, or using len(l) itself as an index. A length-n list's last valid index is n - 1, not n.
Does slicing a list ever raise IndexError?
No. l[2:10] on a 3-item list just returns what exists (possibly an empty list) instead of raising. Only direct indexing (l[10]) raises IndexError. Use slicing when you want a safe 'up to N items' read.
How do I safely check if a list has an item before indexing it?
Use a plain truthiness check: if my_list: my_list[0]. An empty list is falsy, so this also covers the single most common real-world cause of this error - code that assumes a search or query result is never empty.
Written with AI assistance. Measured on 2026-10-03 with Python 3.13.5 on Linux using plain python3 one-liners. Every traceback below is copy-pasted output, not paraphrased. PlainHeaders is our extension; Python is free.