Python JSON: dumps, loads, Type Changes, and Common Errors

Last edited Oct 18, 2026 · 4 min read

JSON is a text format for structured data, and Python's json module turns dictionaries and lists into JSON text (dumps) and JSON text back into dictionaries and lists (loads). A round trip does not always return the same thing you started with: tuples come back as lists, and number keys come back as strings. The module reference documents both. Every example below was run in Python 3.13, and the output shown is what it printed. The reference was read in October 2026.

1. dumps and loads: Python to text and back

The "s" in dumps and loads stands for string. dumps returns a string, and loads takes one.

import json

order = {"id": 7, "items": ["tea", "cake"], "paid": True, "note": None, "total": 12.5}
text = json.dumps(order)
print(text)
print(type(text))
{"id": 7, "items": ["tea", "cake"], "paid": true, "note": null, "total": 12.5}
<class 'str'>

True became true and None became null. The reference gives the full conversion table:

Python JSON
dict object
list, tuple array
str string
int, float number
True / False true / false
None null

Going the other way:

back = json.loads(text)
print(back)
print(back == order)
print(back["items"][1])
{'id': 7, 'items': ['tea', 'cake'], 'paid': True, 'note': None, 'total': 12.5}
True
cake

Here the round trip returned an equal dictionary, because every value was a type JSON represents exactly.

2. Making it readable

indent adds line breaks and spacing, and sort_keys=True orders the keys. Both are options the reference lists for pretty printing.

print(json.dumps(order, indent=2, sort_keys=True))
{
  "id": 7,
  "items": [
    "tea",
    "cake"
  ],
  "note": null,
  "paid": true,
  "total": 12.5
}

Without indent, everything is on one line. The reference also shows separators=(',', ':') for the most compact output.

3. What changes on the round trip

JSON has arrays but no tuples, so a tuple is written as an array and comes back as a list:

data = {"point": (3, 4), "ok": True, "none": None}
print(json.dumps(data))
print(json.loads(json.dumps(data)))
{"point": [3, 4], "ok": true, "none": null}
{'point': [3, 4], 'ok': True, 'none': None}

Keys have a similar rule. The reference states that keys in JSON are always strings, so converting a dictionary with non-string keys and back can produce a dictionary that is not equal to the original:

keys = {1: "one", 2: "two"}
print(json.dumps(keys))
print(json.loads(json.dumps(keys)))
print(json.loads(json.dumps(keys)) == keys)
{"1": "one", "2": "two"}
{'1': 'one', '2': 'two'}
False

If you use IDs as dictionary keys and save them to JSON, convert them back with int() after loading.

4. Non-English text

By default ensure_ascii is true, and the reference says the output then escapes all non-ASCII characters. The text is still valid and loads back correctly, but it is hard to read. Set it to false to keep the characters:

print(json.dumps({"city": "Zürich"}))
print(json.dumps({"city": "Zürich"}, ensure_ascii=False))
{"city": "Z\u00fcrich"}
{"city": "Zürich"}

5. Reading the errors

Invalid JSON raises json.JSONDecodeError. These three strings are common mistakes when writing JSON by hand:

for bad in ["{'a': 1}", '{"a": 1,}', '{"a": True}']:
    try:
        json.loads(bad)
    except json.JSONDecodeError as e:
        print(bad, "->", e)
{'a': 1} -> Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
{"a": 1,} -> Illegal trailing comma before end of object: line 1 column 8 (char 7)
{"a": True} -> Expecting value: line 1 column 7 (char 6)

JSON requires double quotes, does not allow a trailing comma, and spells booleans in lowercase. The error message gives the line and column where parsing stopped, which is where to look first. The exact wording of these messages can differ between Python versions.

Values JSON has no type for raise a TypeError when you write them:

json.dumps({"when": {1, 2}})
TypeError: Object of type set is not JSON serializable

Convert a set with sorted() or list() before dumping it. The reference also describes a default= function for teaching dumps how to handle your own types.

6. Files: dump and load

The tutorial's input and output chapter has a short section on saving structured data with the json module. Without the "s", json.dump(obj, file) writes to an open file and json.load(file) reads from one:

with open("order.json", "w", encoding="utf-8") as f:
    json.dump(order, f, indent=2)
with open("order.json", encoding="utf-8") as f:
    print(json.load(f) == order)
True

7. Key takeaways

  • dumps and loads work with strings; dump and load work with open files.
  • Dict maps to object, list and tuple to array, None to null, True to true.
  • Tuples come back as lists, and non-string dictionary keys come back as strings.
  • Use indent and sort_keys=True for readable output; ensure_ascii=False keeps non-English characters.
  • JSONDecodeError messages give the line and column; double quotes, no trailing commas and lowercase booleans are the usual fixes.
  • Sets and custom objects raise TypeError unless you convert them first.

Sources

  1. Python Software Foundation, json, JSON encoder and decoder
  2. Python Software Foundation, The Python Tutorial, Input and Output (Saving structured data with json)
CategoriesCoding From Zeropythonjsondatabeginners

More on work & tech from other topics