The JSON object must be str, bytes or bytearray — what it means and how to fix it
This is a Python TypeError, not a JSON formatting problem. It happens when json.loads() receives something that isn't already a string, bytes, or bytearray — most commonly because the value passed in is already a Python object (a dict, list, file handle, or HTTP response object) rather than raw JSON text.
Below are the four most common variants of this error and how to fix each one.
1"not dict" or "not list"
This happens when you already have a native Python dict or list and mistakenly call json.loads() on it. The two main functions go in opposite directions: json.dumps() converts a Python object to a JSON string, while json.loads() parses a JSON string back into a Python object. If you already have the object, you don't need to parse it — and if you need JSON text, you need dumps(), not loads().
import json
data = {"name": "Alice", "age": 30}
text = json.loads(data)
# TypeError: the JSON object must be
# str, bytes or bytearray, not dictimport json
data = {"name": "Alice", "age": 30}
text = json.dumps(data)
# '{"name": "Alice", "age": 30}'2"not TextIOWrapper"
This happens when you pass an open file object directly to json.loads() instead of json.load() (no s). The difference: json.load() reads directly from a file-like object, while json.loads() expects a string that has already been read into memory. Either switch to json.load(f), or read the file first with f.read().
import json
with open("config.json") as f:
data = json.loads(f)
# TypeError: the JSON object must be
# str, bytes or bytearray, not
# TextIOWrapperimport json
with open("config.json") as f:
data = json.load(f)
# Reads and parses in one step3"not Response"
This is extremely common when using the requests library. Calling json.loads() on a Response object passes the entire object — not its body text. The requests library already provides a built-in .json() method that handles decoding for you. Alternatively, you can pass response.text to json.loads().
import json, requests
resp = requests.get("https://api.example.com/data")
data = json.loads(resp)
# TypeError: the JSON object must be
# str, bytes or bytearray, not Responseimport requests
resp = requests.get("https://api.example.com/data")
data = resp.json()
# Built-in method, no import json needed4"not coroutine"
In async code (e.g. aiohttp, httpx, or FastAPI), forgetting to await an async function call means you get a coroutine object instead of the actual result. Passing that coroutine to json.loads() triggers this TypeError. The fix is to await the async call first so you receive the resolved string value.
import json, aiohttp
async def fetch():
async with aiohttp.ClientSession() as s:
resp = await s.get("https://api.example.com")
body = resp.text() # missing await!
data = json.loads(body)
# TypeError: ... not coroutineimport json, aiohttp
async def fetch():
async with aiohttp.ClientSession() as s:
resp = await s.get("https://api.example.com")
body = await resp.text()
data = json.loads(body)Already have a JSON string? Validate it instantly.
Paste your JSON into our formatter to check for syntax errors, pretty-print, or minify — all in your browser.