Common causes
1. Python's json.dumps with allow_nan left on
By default json.dumps emits NaN and Infinity, which Python can read back but browsers, Go and Java cannot. Pass allow_nan=False to catch them, and convert them to None before serializing.
payload = json.dumps(stats)clean = {k: (None if isinstance(v, float) and not math.isfinite(v) else v) for k, v in stats.items()}
payload = json.dumps(clean, allow_nan=False)2. Missing values in a pandas DataFrame
Empty cells in pandas are NaN floats. DataFrame.to_json writes them as null, while json.dumps(df.to_dict()) writes NaN. Let pandas do the serialization.
body = json.dumps(df.to_dict(orient='records'))body = df.to_json(orient='records')3. The value really is unbounded or undefined
If the consumer needs to know a limit is infinite or a measurement failed, say so explicitly. null means “no value”; a string or a flag keeps the meaning.
{"mean": NaN, "max": Infinity}{"mean": null, "max": "Infinity", "maxUnbounded": true}4. Text copied from a console instead of serialized
console.log and Node’s util.inspect print NaN and Infinity as they are. Copy the output of JSON.stringify(value) instead; it writes null for non-finite numbers.
console.log(result);console.log(JSON.stringify(result, null, 2));Frequently asked questions
Why does JSON not support NaN?
JSON numbers are defined as decimal digit sequences so that every language can represent them. NaN and Infinity are IEEE 754 floating-point concepts that not all platforms share, so they were left out.
Why does my Python code read NaN without complaint?
Python’s json.loads accepts NaN, Infinity and -Infinity as an extension. Strict parsers in browsers, Go, Java and most databases do not, so the file only works in Python.
What does JSON.stringify do with NaN?
It writes null, for NaN, Infinity and -Infinity alike. The data loses the distinction silently, which is why explicit handling is better.