TypeError: list indices must be integers or slices, not str
1 · The lesson
readWhat this error means
You indexed a list with a string, like users["name"]. You get list items by position (users[0], users[1]), not by key. You can only use a string subscript on a dict. Python is telling you it expected an integer position (or a slice like users[0:2]) and got a string instead.
When you see it
Traceback (most recent call last): File "main.py", line 4, in <module> name = users["name"] TypeError: list indices must be integers or slices, not str
Why it happens
Almost always: you got a list of dicts back from json.loads(...), a database query, or an API call, and treated the whole list as if it were a single dict.
import json raw = '[{"name": "alice"}, {"name": "bob"}]' users = json.loads(raw) # this is a LIST of dicts, not a dict print(users["name"]) # TypeError
The fix is almost always to index into the list first and then into the dict, or to loop over the list.
How to fix it
Index by position, then by key:
users = [{"name": "alice"}, {"name": "bob"}]
print(users[0]["name"]) # aliceLoop when you want every element:
for user in users: print(user["name"])
setup added so this can run · re-runs 2 earlier blocks on this page first
users = [{"name": "alpha"}, {"name": "beta"}, {"name": "gamma"}]
# Earlier blocks on this page that this one builds on, re-run quietly first.
try:
import json
except Exception:
pass
_pm_earlier = [
'import json\nraw = \'[{"name": "alice"}, {"name": "bob"}]\'\nusers = json.loads(raw) # this is a LIST of dicts, not a dict\nprint(users["name"]) # TypeError',
'users = [{"name": "alice"}, {"name": "bob"}]\nprint(users[0]["name"]) # alice',
]
def _pm_run_earlier(_srcs, _g):
import sys as _s, io as _io, warnings as _w
for _src in _srcs:
_o, _e = _s.stdout, _s.stderr
_s.stdout = _s.stderr = _io.StringIO()
try:
with _w.catch_warnings():
_w.simplefilter('ignore')
exec(compile(_src, '<earlier block>', 'exec'), _g)
except (Exception, SystemExit):
pass
finally:
_s.stdout, _s.stderr = _o, _e
if 'matplotlib.pyplot' in _s.modules:
_s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks
_pm_run_earlier(_pm_earlier, globals())
del _pm_earlier, _pm_run_earlierUse a list comprehension to extract a column:
names = [u["name"] for u in users]
setup added so this can run · re-runs 2 earlier blocks on this page first
users = [{"name": "alpha"}, {"name": "beta"}, {"name": "gamma"}]
# Earlier blocks on this page that this one builds on, re-run quietly first.
try:
import json
except Exception:
pass
_pm_earlier = [
'import json\nraw = \'[{"name": "alice"}, {"name": "bob"}]\'\nusers = json.loads(raw) # this is a LIST of dicts, not a dict\nprint(users["name"]) # TypeError',
'users = [{"name": "alice"}, {"name": "bob"}]\nprint(users[0]["name"]) # alice',
]
def _pm_run_earlier(_srcs, _g):
import sys as _s, io as _io, warnings as _w
for _src in _srcs:
_o, _e = _s.stdout, _s.stderr
_s.stdout = _s.stderr = _io.StringIO()
try:
with _w.catch_warnings():
_w.simplefilter('ignore')
exec(compile(_src, '<earlier block>', 'exec'), _g)
except (Exception, SystemExit):
pass
finally:
_s.stdout, _s.stderr = _o, _e
if 'matplotlib.pyplot' in _s.modules:
_s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks
_pm_run_earlier(_pm_earlier, globals())
del _pm_earlier, _pm_run_earlierOr restructure the data into a dict-by-id, if you'll be doing many lookups:
users = [{"id": 41, "name": "alice"}, {"id": 42, "name": "bob"}]
users_by_id = {u["id"]: u for u in users}
print(users_by_id[42]["name"])When you'd see this in real code
json.loads(response.text)returned a list, not a dict. You assumed the wrong shape for the API response.- You turned a
csv.DictReaderinto a list (rows = list(reader)), which gives a list of dicts, and then wroterows["column"]instead of looping. - An ORM query returned multiple rows, but you treated the whole result set as one row.
- You stored a list in a variable named like a dict (
config = [...]) and later wroteconfig["host"].
Related errors
- TypeError: 'int' object is not subscriptable: a related mistake, where you treated an int as if it could be indexed.
- KeyError: when you index a dict with a key that isn't there.
- AttributeError: 'list' object has no attribute 'X': calling dict methods on lists.
See Also
- All Python errors: the full index, by type and by when it happens.
- Lists (tutorial)
- Dictionaries (tutorial)
- CSV and JSON how-to
- List comprehensions
Found this useful? Share it with a friend who’s learning Python.