pythonseverity: can-fix
IndexError

Python IndexError: list index out of range

IndexError: list index out of range

98% fixable~5 mindifficulty: beginner

Verified against CPython 3.13 source (Objects/listobject.c), Python docs: built-in-exceptions, Python docs: tutorial/datastructures · Updated April 2026

> quick_fix

You accessed a list, tuple, or string at an index that doesn't exist. Either the index is too large (>= len(seq)), too negative (< -len(seq)), or the sequence is empty. Check len() before indexing, or use try-except IndexError if missing-index is a normal case.

# Raises IndexError if list is empty or shorter than expected
first = items[0]

# Fix - check first
if items:
    first = items[0]
else:
    first = None

# Or use slicing (returns empty, not error)
first = items[:1]

# Or use a default
first = next(iter(items), None)

What causes this error

Python's sequence types raise IndexError when you ask for a position that isn't there. Lists are 0-indexed, so the last valid index is len(list) - 1. Negative indices count from the end, so -1 is the last item. Anything outside [-len, len-1] raises IndexError immediately - Python does not silently return None or extend the list.

> advertisementAdSense placeholder

How to fix it

  1. 01

    step 1

    Print the length of the sequence and the index you're using

    Add a print(len(items), i) above the failing line. The mismatch is usually obvious.

  2. 02

    step 2

    Check for off-by-one errors

    for i in range(len(items)): items[i] is fine. But for i in range(len(items) + 1): items[i] is off by one.

  3. 03

    step 3

    Use slicing for safe access

    items[100:101] returns [] if items has fewer than 100 elements - never raises. Same for items[-100:-99]. Slicing is forgiving where indexing is not.

  4. 04

    step 4

    For dictionaries, use .get() with default

    But if you're seeing IndexError on a dict, you're probably indexing a value that should be a list. Re-read the error message and verify the type of the variable.

  5. 05

    step 5

    Wrap in try-except IndexError when missing-index is expected

    Common in 'pop until empty' loops or input parsing. But for normal access, prefer the explicit length check.

    try:
        first = items[0]
    except IndexError:
        first = None

How to verify the fix

  • The IndexError no longer fires.
  • Empty-sequence case handled (returns sensible default).
  • Loop bounds match len(seq) exactly.

Why IndexError happens at the runtime level

Python's list, tuple, and string types implement the sq_item slot in their PySequenceMethods table. When you access seq[i], the interpreter calls PySequence_GetItem which invokes the type's sq_item with the normalised index. The implementation in Objects/listobject.c (list_item) compares the index against ob_size (the list's length); if i >= size or i < -size, it raises PyExc_IndexError immediately with a fixed 'list index out of range' message. The check is unconditional and there's no auto-extension - Python's design treats out-of-bounds access as a programmer error, not a runtime fallback.

Common debug mistakes for IndexError

  • Looping while True and incrementing an index instead of using for-each - the index passes the end and IndexError fires; for item in items handles bounds automatically.
  • Using items[-1] on a possibly-empty list expecting None - empty lists have no last item and raise IndexError just like positive overflow.
  • Calling sys.argv[1] without checking len(sys.argv) - if the user runs the script with no arguments, IndexError fires immediately and the message is unhelpful for end-users.
  • Splitting a string by a delimiter and indexing parts[1] without confirming the delimiter was present - 'foo'.split(':') returns ['foo'] and [1] raises.
  • Modifying a list during iteration with items.pop() and continuing the loop - the index becomes stale and IndexError fires before the loop's natural end.

When IndexError signals a deeper problem

IndexError that returns under load usually signals an off-by-one in a hot path that worked on test fixtures but fails on real input. The architectural cause is direct indexing into structures that should be iterated or destructured. Replace items[0], items[1], items[2] = a, b, c with explicit unpacking (a, b, c = items, with a length assertion or itertools fill) and the IndexError converts into a clearer ValueError at the unpack boundary. For nested data, use safe-navigation libraries (operator.itemgetter, jmespath, get with default). Without a typed boundary, the IndexError will keep returning every time the upstream data shape changes.

Frequently asked questions

What's the difference between IndexError and KeyError?

IndexError - integer index missing on a sequence (list, tuple, string). KeyError - hashable key missing on a mapping (dict, set). Different exception types, same idea.

Why doesn't Python auto-extend a list when I assign past the end?

By design - it would mask off-by-one bugs and make code unpredictable. To grow a list, use append() or extend().

Can a string raise IndexError?

Yes. Strings are sequences, so 'abc'[5] raises IndexError. Same rules as lists.

disclosure:Errordex runs AdSense, has zero third-party affiliate or sponsored links, and occasionally links to the editor’s own paid digital products (clearly labelled). Every fix is manually verified against official sources listed in the “sources” sidebar. If a fix here didn’t work for you, please email so we can update the page.