Python's nonstandard JSON encoding
This was last updated for Python 3.11.4.
Python’s built-in JSON module, json, can produce results that most other JSON parsers do not accept. This is because it has nonstandard serializations for infinity, negative infinity, and NaN.
import json
import math
json.dumps([math.inf, -math.inf, math.nan])
# => "[Infinity, -Infinity, NaN]"
Most other languages and libraries can’t decode this. For example, JSON.parse("Infinity") throws an error in JavaScript.
To avoid this, you can pass the allow_nan option, which will throw an error if you try to serialize these values. (Though it’s called “allow NaN”, it also throws if passed inf.)
json.dumps(math.nan, allow_nan=False)
# ValueError: Out of range float values are not JSON compliant
json.dumps(math.inf, allow_nan=False)
# ValueError: Out of range float values are not JSON compliant
I tested the following languages and libraries, all of which fail to parse these values:
- C++: nlohmann::json
- Clojure: data.json
- Crystal:
JSON.parse() - Dart:
json.decode() - Go: encoding/json
- Java: Jackson
- Java: org.json parses unquoted strings so these values are parsed as the string “Infinity” or “NaN”, but this is not a special case. For example, this is no different from parsing the string “foo”.
- JavaScript:
JSON.parse() - PHP:
json_decode() - Ruby:
JSON.parse()fails by default, though theallow_nanoption will parse these values - Rust: Serde JSON
- Swift:
JSONSerialization.jsonObject(with:)
However, there are a few places that parse these just fine:
- Python, of course
- Java’s Gson
- jq, which also parses
infand-inf - SQLite’s JSON functions, though its
json_valid()function returns0for these strings
These values are also valid JSON5. JSON5 “is not intended to be used for machine-to-machine communication”, but can parse the values “Infinity”, “-Infinity”, and “NaN”.
I found Python’s behavior pretty surprising, so I thought I’d write it up!