TypeError: string indices must be integers (tested fix)
TypeError: string indices must be integers, not 'str' means the value you indexed with ["key"] is a string, not a dict. With JSON there are three usual causes, and we reproduced each in Python 3.13.
1. You have a string where you expected a dict
x["key"] on a str raises this error. With JSON it happens three ways: the text was never parsed, a loop over a dict gives you its keys (strings), or the JSON was encoded twice:
import json
raw = '{"user": {"name": "ann"}}'
for label, expr in [("json text, not parsed", 'raw["user"]'), ("loop over dict keys", '[k["name"] for k in json.loads(raw)]'), ("double-encoded JSON", 'json.loads(json.dumps(raw))["user"]')]:
try:
print(f"{label:22} OK -> {eval(expr)!r}")
except TypeError as e:
print(f"{label:22} TypeError: {e}")
Output:
json text, not parsed TypeError: string indices must be integers, not 'str'
loop over dict keys TypeError: string indices must be integers, not 'str'
double-encoded JSON TypeError: string indices must be integers, not 'str'
2. The fix for each
import json
raw = '{"user": {"name": "ann"}}'
data = json.loads(raw) # parse first
print(data["user"]["name"])
for key, value in data.items(): # iterating a dict gives keys; use .items()
print(key, value["name"])
twice = json.dumps(raw) # JSON text encoded again -> a JSON *string*
print(type(json.loads(twice)).__name__, json.loads(json.loads(twice))["user"])
Output:
ann
user ann
str {'name': 'ann'}
Parse with json.loads() (or response.json()) before indexing. Iterate a dict with .items() when you need values. If json.loads() returns a str, the data was JSON-encoded twice; the real fix is to stop calling json.dumps() on text that is already JSON. To find which case you have, print(type(x), repr(x)[:80]) just before the failing line. For the list version of this error, see list indices must be integers or slices, not str.
Frequently asked questions
How do I fix string indices must be integers with JSON?
Parse it first: data = json.loads(text) (or response.json()), then data['key'].
Why does looping over a dict give string indices must be integers?
for k in d gives the keys, which are strings. Use for k, v in d.items() and index v.
Why does json.loads return a string?
The JSON was encoded twice (json.dumps on text that was already JSON). Remove the extra dumps.
Written with AI assistance. Measured on 2026-10-22 on Debian with Python 3.13.5: indexing unparsed JSON text, dict keys from a loop, and double-encoded JSON with a key, and the json.loads, .items() and decode-twice fixes. Every block was run verbatim and its output pasted unedited. PlainHeaders is our extension; Python is free.