TypeError: the JSON object must be str, bytes or bytearray, not dict

Quick answer

json.loads() parses JSON text into a Python object. This error means you handed it something already parsed — a dict, list, or None. The fix is to not call json.loads at all and use the value directly, or to pass the raw text (e.g. response.text) instead of the parsed result.

The exact error string

import json

data = {"name": "Ada"}          # already a dict
json.loads(data)

Traceback (most recent call last):
  File "app.py", line 4, in <module>
    json.loads(data)
TypeError: the JSON object must be str, bytes or bytearray, not dict

json.loads() accepts only str, bytes, or bytearray. Passing a Python object such as a dict, list, None, or a file object raises this TypeError.

json.loads ("load string") turns text into an object. If you already have the object, there is nothing to parse — calling it is the bug. The trailing word (dict, list, NoneType) tells you what you actually passed.

Cause 1: double-parsing a requests response

By far the most common case: wrapping response.json() — which already returns a dict — in another json.loads:

import requests
resp = requests.get("https://api.example.com/user")

# ❌ response.json() is already a dict
data = json.loads(resp.json())        # TypeError: ... not dict

# ✅ pick one:
data = resp.json()                    # parsed dict (recommended)
data = json.loads(resp.text)          # parse the raw text yourself

Cause 2: the value is None

not NoneType means the value was None — commonly a dict.get() miss, an empty environment variable, or a function that returned nothing:

payload = config.get("body")          # key missing -> None
json.loads(payload)                   # TypeError: ... not NoneType

# ✅ guard for None before parsing
if payload is not None:
    data = json.loads(payload)
else:
    data = {}

Cause 3: json.loads vs json.load on a file

Use json.load for an open file object and json.loads for a string. Mixing them is a frequent trigger:

# ❌ Wrong — f is a file object, not text
with open("data.json") as f:
    data = json.loads(f)

# ✅ Option 1 — json.load reads AND parses the file object
with open("data.json") as f:
    data = json.load(f)

# ✅ Option 2 — read to text first, then json.loads
with open("data.json") as f:
    data = json.loads(f.read())

Cause 4: it is already a list

not list means the value is an already-parsed array. Don't re-parse it — iterate or index it directly:

rows = resp.json()                    # already a list of dicts
json.loads(rows)                      # ❌ TypeError: ... not list
for row in rows:                      # ✅ use it directly
    print(row["id"])

Debugging checklist

Frequently Asked Questions

What does 'the JSON object must be str, bytes or bytearray, not dict' mean?

It means you passed json.loads() something that is already a Python object — a dict (or list, or None) — instead of JSON text. json.loads parses a string into an object; if you already have the object, you do not call json.loads at all. Use the value directly.

How do I fix it with requests?

Do not wrap response.json() in json.loads(). response.json() already returns a parsed dict, so json.loads(response.json()) passes a dict and fails. Either use response.json() alone, or json.loads(response.text) — never both.

Why does 'not list' or 'not NoneType' appear?

Same error, different value. not list means you passed an already-parsed array; not NoneType means the value was None — often because a .get() returned None or a function returned nothing. Trace where the value came from and pass JSON text, or skip the parse if it is already an object.

What is the difference between json.load and json.loads?

json.load(f) reads and parses from a file object; json.loads(s) parses from a string. Passing a file object to json.loads, or a dict to either, raises a TypeError. Use json.load for an open file and json.loads for a string you already read.

How do I check whether I even need json.loads?

Print type() of the value. If it is already dict or list, you are done — index it directly. Only call json.loads when type() is str or bytes. Calling json.loads on something already parsed is the whole cause of this error.

Is this the opposite of 'string indices must be integers'?

Effectively yes. string indices must be integers is indexing a string you forgot to parse; "the JSON object must be str... not dict" is parsing an object you already parsed. Both come from being unsure whether a value is text or a Python object — check its type once and the right call is obvious.

Inspect what your API actually returns

Paste the raw response into the formatter to confirm whether it's text to parse or already an object — nothing is uploaded to a server.

JSON Formatter JSON Validator All Error References
About the author

Pasindu Ishan is a software developer based in Sri Lanka. He builds privacy-first developer tools at JSON Dev Tools.