TypeError: 'str' / 'tuple' object does not support item assignment (tested fix)

TypeError: 'str' object does not support item assignment (or 'tuple') means you tried x[i] = value on an immutable type. We reproduced it on six types in Python 3.13 and tested the fixes, including a case where the change happens even though the error is raised.

1. Which types are immutable

obj[i] = value only works on mutable containers such as list, dict and bytearray. Strings, tuples and a few other built-ins can't be changed in place, so item assignment raises TypeError with the type name in the message. We tried six types:

cases = {"str": "hello", "tuple": (1, 2, 3), "bytes": b"abc", "range": range(3), "frozenset": frozenset({1}), "dict_keys": {}.keys()}
for name, obj in cases.items():
    try:
        obj[0] = 9
        print(f"{name:10} OK")
    except TypeError as e:
        print(f"{name:10} TypeError: {e}")

Output:

str        TypeError: 'str' object does not support item assignment
tuple      TypeError: 'tuple' object does not support item assignment
bytes      TypeError: 'bytes' object does not support item assignment
range      TypeError: 'range' object does not support item assignment
frozenset  TypeError: 'frozenset' object does not support item assignment
dict_keys  TypeError: 'dict_keys' object does not support item assignment

2. The fix: build a new value

You can't change a string or tuple, but you can build a new one and rebind the name. Slice and concatenate, or convert to a list, edit it, and convert back:

s = "hello"
s2 = "j" + s[1:]                 # slice and rebuild
chars = list(s); chars[0] = "j"  # or edit a list, then join
print(s2, "".join(chars), s.replace("h", "j", 1))

t = (1, 2, 3)
t2 = t[:1] + (9,) + t[2:]        # build a new tuple
lst = list(t); lst[1] = 9
print(t2, tuple(lst))

Output:

jello jello jello
(1, 9, 3) (1, 9, 3)

For bytes, use a bytearray. It is mutable, so b = bytearray(b"abc"); b[0] = 106 works and gives bytearray(b'jbc').

3. The common trap: a string inside a dict or list

The container is mutable, but the value you indexed into isn't. Here the second [0] targets the str, not the dict:

d = {"name": "ann"}
d["name"][0] = "A"     # the str inside the dict, not the dict

Output:

Traceback (most recent call last):
  File "/tmp/ia/b3.py", line 2, in <module>
    d["name"][0] = "A"     # the str inside the dict, not the dict
    ~~~~~~~~~^^^
TypeError: 'str' object does not support item assignment

Assign a new string to the key instead. A related surprise goes the other way: a list inside a tuple can be mutated, and t[0] += [4] raises the TypeError after it has already extended the list:

d = {"name": "ann"}
d["name"] = "A" + d["name"][1:]   # assign a new string to the dict key
print(d)

t = ([1, 2], "x")
t[0].append(3)                    # mutating a list INSIDE a tuple works
print(t)
try:
    t[0] += [4]                   # but += on a tuple item raises... after mutating
except TypeError as e:
    print("TypeError:", e)
print(t)

Output:

{'name': 'Ann'}
([1, 2, 3], 'x')
TypeError: 'tuple' object does not support item assignment
([1, 2, 3, 4], 'x')

That happens because += on a list mutates it in place first, and only then tries to store the result back into the tuple slot. Use t[0].extend(...) or t[0].append(...) to avoid the half-applied error.

4. namedtuple: a different error

Setting a namedtuple field by attribute gives AttributeError, not TypeError. Use _replace to get a modified copy:

from collections import namedtuple
P = namedtuple("P", "x y")
p = P(1, 2)
try:
    p.x = 5
except AttributeError as e:
    print("AttributeError:", e)
print(p._replace(x=5))

Output:

AttributeError: can't set attribute
P(x=5, y=2)

If you need fields you can edit, use a dataclass or a dict instead. For the related read-side error, see object is not subscriptable.

Frequently asked questions

How do I fix 'str' object does not support item assignment?

Strings are immutable. Build a new one: s = s[:i] + 'x' + s[i+1:], or edit list(s) and ''.join() it back.

How do I change a value in a tuple?

Build a new tuple (t[:i] + (v,) + t[i+1:]) or convert with list(t), edit, and convert back with tuple().

Why did my list inside a tuple change even though += raised TypeError?

list += mutates the list in place first, then the tuple refuses the store. Use .extend() or .append() on the inner list instead.

Written with AI assistance. Measured on 2026-10-22 on Debian with Python 3.13.5: item assignment on str, tuple, bytes, range, frozenset and dict_keys, the rebuild fixes, a str inside a dict, += on a list inside a tuple, and namedtuple fields. Every block was run verbatim and its output pasted unedited. PlainHeaders is our extension; Python is free.