reference
3 min read
·
lesson 13 of 45 in Errors
IndexError: string index out of range
1 · The lesson
readWhat this error means
You indexed into a string at a position that doesn't exist. Strings, like lists, are zero-indexed sequences: "abc"[0] is 'a', "abc"[2] is 'c', and "abc"[3] raises IndexError. An empty string "" has no valid indices at all.
When you see it
python
>>> name = "Margaret" >>> name[10] Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: string index out of range
Why it happens
It almost always shows up in parsing code that assumes a fixed structure — a date string that is always YYYY-MM-DD, a postcode that is always 6 characters, a filename that always has an extension. When the input deviates by even one character, the assumed index lands past the end.
How to fix it
1. Validate length first:
python
def first_letter(s): if len(s) == 0: return "" return s[0]
2. Use slicing — slices never raise:
python
year = date_str[:4] # safe even if date_str is shorter suffix = filename[-3:] # safe on any string
setup added so this can run · defines date_str, filename
date_str = ["alpha", "beta", "gamma"] filename = ["alpha", "beta", "gamma"]
3. Use str methods designed for the job rather than hand-rolled indexing:
python
# brittle ext = filename[filename.index(".") + 1:] # robust import os ext = os.path.splitext(filename)[1].lstrip(".")
setup added so this can run · defines filename
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) filename = _AutoMock('filename')
4. Catch when parsing genuinely unknown input:
python
try: initial = user_input[0].upper() except IndexError: initial = "?"
setup added so this can run · defines user_input
user_input = ["alpha", "beta", "gamma"]
When you'd actually see this in real code
- Reading a CSV where one row has an empty trailing field:
row[0][0]blows up becauserow[0]is"". - Parsing a phone number assuming a country code prefix:
number[1:4]is fine, butnumber[0]raises on an empty string. - Walking through a string character-by-character with an explicit counter that increments past the end inside a
whileloop. Preferfor ch in s:orenumerate(s).
Related errors
See Also
- All Python errors — the full index, by type and by when it happens.
- String cheat sheet
- Strings and slicing tutorial