NaN and Infinity are not valid JSON

JSON numbers must be finite decimal numbers, so NaN, Infinity and -Infinity are not valid values. JavaScript’s JSON.stringify quietly writes them as null, but Python’s json module writes them as bare words, and other parsers then fail on the N or I. Decide what the value should mean to the reader, then send null, a string or a sentinel number.

Seen as:

  • SyntaxError: Unexpected token 'N', ..." "mean": NaN, "ma"... is not valid JSON
  • SyntaxError: Unexpected token N in JSON at position 33
  • SyntaxError: JSON.parse: unexpected character at line 3 column 11 of the JSON data
  • json: unsupported value: NaN
  • ValueError: Out of range float values are not JSON compliant: nan

Input

Settings

History

Load from URL

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.

Before
payload = json.dumps(stats)
After
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.

Before
body = json.dumps(df.to_dict(orient='records'))
After
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.

Before
{"mean": NaN, "max": Infinity}
After
{"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.

Before
console.log(result);
After
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.

Related