← Back

Home › Errors › IndexError

IndexError: string index out of range

Exception: IndexErrorCategory: runtime (indexing)Raised at: the s[i] expression whose index is outside the string's valid range

What this error means

You indexed into a string at a position that does not exist. A string of length n has exactly n characters, and each one has a valid index. Ask for anything outside that set and Python raises IndexError.

Traceback (most recent call last):
  File "demo.py", line 2, in <module>
    first = name[0]
IndexError: string index out of range

The valid range is small enough to memorise:

s = "hello"        # len(s) == 5

# forward: 0 to len(s)-1
s[0] == 'h'   s[1] == 'e'   s[4] == 'o'
s[5]                      # 💥 one past the end
s[len(s)]                 # 💥 the classic off-by-one

# backward: -1 to -len(s)
s[-1] == 'o'   s[-5] == 'h'
s[-6]                     # 💥 one before the start

s[len(s) - 1] == 'o'      # ✅ the correct way to write "last character"

The five ways to go past the end

# 1 — the off-by-one loop, by far the most common
for i in range(len(s) + 1):      # ❌ range should be len(s)
    print(s[i])
for i in range(len(s)):          # ✅

# 2 — indexing an empty string
s = ""
s[0]                             # 💥 an empty string has no valid index at all

# 3 — comparing neighbours without stopping one early
for i in range(len(s)):
    if s[i] == s[i + 1]:         # 💥 on the last iteration
        ...
for i in range(len(s) - 1):      # ✅ stops one short
    if s[i] == s[i + 1]:
        ...

# 4 — s[-1] on an empty string
lines = f.read().split("\n")
last = lines[-1]                 # 💥 if the file was empty

# 5 — assuming a fixed shape
initial = full_name[0]           # 💥 when full_name is ""

Cause 2 and cause 4 are the same bug wearing different clothes: the container might be empty. Every guard for this error is really a guard against emptiness, which is why checking the length first fixes so many cases.

Why slicing never raises but indexing always does

This asymmetry trips people up constantly, and it is deliberate. Indexing asks for one specific character — if it is not there, that is an error. Slicing asks for a range, and an empty range is a perfectly valid answer:

s = "hi"
s[5]          # 💥 IndexError
s[5:9]        # ✅ ''      — out-of-range slices just give an empty string
s[:100]       # ✅ 'hi'    — clamped to what exists
s[1:100]      # ✅ 'i'
s[::-1]       # ✅ 'ih'

s = ""
s[0]          # 💥 IndexError
s[:]          # ✅ ''      — even on an empty string

So if you want a character but would rather have an empty string than an exception, slice it: s[0:1] returns '' on an empty string instead of raising. That is a legitimate idiom, not a hack — though an explicit length check usually reads better.

The fixes

# guard the emptiness
if s:
    first = s[0]

# or use a default
first = s[0] if s else ""

# iterate the characters, not the indexes — then the bug cannot happen
for ch in s:
    print(ch)

# when you need the position, use enumerate
for i, ch in enumerate(s):
    print(i, ch)

# comparing neighbours
for a, b in zip(s, s[1:]):
    if a == b:
        ...

# the last character, safely
last = s[-1] if s else None

Iterating the characters directly removes the whole class of bug. for ch in s cannot go out of range, because there are no indexes to get wrong. Reach for range(len(s)) only when you genuinely need the position, and prefer enumerate(s) when you need both.

Strings versus lists

The message differs only in the word string, but the rules are identical for every sequence in Python:

s = "hello"
s[5]              # IndexError: string index out of range

lst = [1, 2, 3]
lst[5]            # IndexError: list index out of range

t = (1, 2)
t[5]              # IndexError: tuple index out of range

One difference is worth knowing: strings and tuples are immutable, so an out-of-range write produces a different error first. s[0] = 'x' fails with TypeError: 'str' object does not support item assignment before any index is even checked.

Related messages worth knowing

🇮🇳 Hindi में समझें

IndexError: string index out of range tab aata hai jab aap string ko aisi position par access karte ho jo exist hi nahi karti. Jis string ki length n hai usme exactly n characters hote hain. Valid range chhoti hai, yaad kar lo: aage ki taraf 0 se len(s)-1 tak, aur peeche ki taraf -1 se -len(s) tak. s[len(s)] hamesha fail hoga — ye classic off-by-one hai. Paanch common wajah: (1) range(len(s) + 1) likh diya, jabki range(len(s)) hona chahiye — ye sabse common hai. (2) Khaali string ko index karna — s = '' par s[0] fail, kyunki koi valid index hi nahi. (3) Padosi characters compare karna bina ek pehle rukke — s[i] == s[i+1] last iteration par fail hoga, isliye range(len(s) - 1) likho. (4) Khaali list ya string par s[-1]. (5) Ye maan lena ki value hamesha bhari hogi, jaise full_name[0]. Ek confusing baat: slicing kabhi error nahi deta, indexing hamesha deta hai. s[5] IndexError dega lekin s[5:9] chupchaap '' de dega, kyunki indexing ek specific character maangti hai jabki slicing ek range maangti hai — aur khaali range ek valid jawab hai. Sabse accha fix: indexes par loop mat chalao, seedha characters par chalao — for ch in s: out of range ho hi nahi sakta. Position chahiye ho to enumerate(s) use karo.

IndexError Hindi में पढ़ें →