Common causes
1. print() or str() on a dict
Printing a dict shows its Python representation, not JSON. Besides the capitalised literals it also uses single quotes. Serialize with json.dumps.
logger.info("payload=%s", payload)logger.info("payload=%s", json.dumps(payload))2. JSON built with an f-string
Formatting a bool into a string gives True, and None gives None. Let the serializer translate Python values into JSON values.
body = f'{{"user": "{user}", "active": {active}, "manager": {manager}}}'body = json.dumps({"user": user, "active": active, "manager": manager})3. Jinja or Ansible templates rendering Python values
In a Jinja template, {{ enabled }} renders a Python bool as True. Use the tojson filter ({{ enabled | tojson }}) so the rendered file contains true.
{"enabled": True, "replicas": 3, "owner": None}{"enabled": true, "replicas": 3, "owner": null}4. Converting a value that is already a dict
Calling json.loads(str(data)) on data that is already a dict fails on the quotes and literals. If you have the object, use it directly; if you need a copy, use copy.deepcopy.
config = json.loads(str(response_data))config = response_dataFrequently asked questions
Why does Python not write JSON when I print a dict?
print calls repr-style formatting meant for Python developers. It happens to look like JSON for simple data, but differs in quotes, literals and in values such as tuples or datetimes. Only json.dumps guarantees JSON output.
Can I parse Python-style text in Python?
Yes: ast.literal_eval safely evaluates a dict literal written with True, None and single quotes. Use it to recover existing data, then save it with json.dumps.
Does Fix it handle single quotes too?
Yes. Python dict output usually has both problems, and Fix it converts single quotes and True, False and None in one pass, showing every change as a diff.