json.dumps() sort_keys=True TypeError (tested)
A dict with mixed-type keys serializes just fine with plain json.dumps(). Add sort_keys=True for deterministic output and the exact same dict can suddenly raise a TypeError. We measured which key-type combinations break and why.
1. Works without sort_keys, breaks with it
import json
d = {1: "a", "b": 2}
json.dumps(d)
'{"1": "a", "b": 2}'
json.dumps(d, sort_keys=True)
TypeError: \'<\' not supported between instances of \'str\' and \'int\'
Measured: without sort_keys, json.dumps() keeps insertion order and never needs to compare keys to each other — it just converts each key to its string form independently. sort_keys=True sorts the original Python key objects before converting them to strings, and Python can't order an int against a str with <, so it raises before serialization even starts.
2. All-int or all-str keys sort fine — the problem is mixing types
json.dumps({2: "a", 1: "b"}, sort_keys=True)
'{"1": "b", "2": "a"}'
json.dumps({"b": 1, "a": 2}, sort_keys=True)
'{"a": 2, "b": 1}'
Measured: both of these work correctly and sort as expected — the bug only appears once a single dict mixes key types that Python's < operator can't compare, which makes it easy to miss in testing if your test data happens to use one key type consistently.
3. Some mixes are safe: bool and float compare fine with int
json.dumps({True: "a", 2: "b"}, sort_keys=True)
'{"true": "a", "2": "b"}'
json.dumps({1.5: "a", 2: "b"}, sort_keys=True)
'{"1.5": "a", "2": "b"}'
Measured: bool is a subclass of int in Python (True == 1) and float/int compare numerically, so both of these sort without error. None mixed with anything else does not: json.dumps({None: "a", "b": "c"}, sort_keys=True) raises the same '<' not supported between instances of 'str' and 'NoneType' style error. The safe combinations are int/float/bool together, or an all-str dict — anything crossing the numeric/string/None boundary breaks.
4. The fix: normalize keys to one type before dumping
d = {1: "a", "b": 2}
json.dumps({str(k): v for k, v in d.items()}, sort_keys=True)
'{"1": "a", "b": 2}'
Measured: converting every key to str yourself before calling json.dumps() sidesteps the comparison entirely, since sort_keys then only ever sorts strings against strings. This is also usually the right fix conceptually — JSON object keys are always strings anyway, so a dict with genuinely mixed-type Python keys was already relying on json.dumps()'s automatic (unsorted) stringification, and making that explicit avoids the surprise entirely.
5. Why this bites people in practice
This almost always shows up when sort_keys=True is added later — for reproducible test fixtures, diff-friendly output, or canonical hashing of a JSON blob — to a dict that was built from mixed sources: some keys from a database (int IDs) merged with some keys from user input or config (str names). The call worked in every test until a dict exercised both key types in the same object at once.
Frequently asked questions
Why does sort_keys=True make json.dumps() raise a TypeError when the same dict works without it?
We confirmed that without sort_keys, json.dumps() converts each key to a string independently with no comparison; sort_keys=True sorts the original Python key objects first using <, and Python can't order an int against a str, so it raises before any string conversion happens.
Does json.dumps(sort_keys=True) fail on all dicts with non-string keys?
No — we measured that all-int or all-str dicts sort correctly; the error only occurs when a single dict mixes key types that Python's < operator can't compare directly against each other.
Are int and bool keys safe to mix with sort_keys=True?
Yes — we confirmed bool and int sort together without error since bool is a subclass of int in Python (True == 1), and float mixes with int fine too since both compare numerically; it's crossing into str or None that breaks.
What's the fix for a TypeError from json.dumps(sort_keys=True) on mixed keys?
We tested converting every key to str yourself before calling json.dumps() — for example {str(k): v for k, v in d.items()} — which sidesteps the comparison entirely since sort_keys then only ever compares strings to strings.
When does this error typically show up in real code?
In our experience it surfaces when sort_keys=True gets added later for deterministic test output or canonical hashing, applied to a dict merged from multiple sources — say int IDs from a database plus str keys from user input — that happened to never exercise both key types in the same dict during earlier testing.
Written with AI assistance. Measured on 2026-10-03 with Python 3.13.5's built-in json module, calling json.dumps() with sort_keys=True on dicts with mixed key types and printing the exact exception text. Every message below is copy-pasted output, not paraphrased. PlainHeaders is our extension; Python's json module is built in.