JSON NaN and Infinity Are Not Valid – How to Handle Them

NaN (Not a Number) and Infinity are valid JavaScript number values, but they have no representation in the JSON specification. If you try to serialize them with JSON.stringify(), you will not get an error — you will get silent data corruption. Understanding this behavior is essential for building reliable APIs.

What JSON.stringify does with NaN and Infinity

JSON.stringify({ ratio: NaN });       // '{"ratio":null}'
JSON.stringify({ max: Infinity });    // '{"max":null}'
JSON.stringify({ min: -Infinity });   // '{"min":null}'

No exception is thrown. The values become null. The receiver on the other end of the API gets null where you intended a numeric special value — and may have no way to tell the difference between "this was NaN" and "this field was genuinely missing."

Why JSON does not support them

The JSON number grammar covers finite decimal numbers only. NaN and Infinity are IEEE 754 floating-point sentinels. Many languages that consume JSON (Python, Java, Go, Ruby) represent these differently or not at all. Including them in JSON would break cross-language interoperability, which is the core purpose of the format.

Detecting NaN and Infinity before serializing

The safest approach is to screen for these values before serialization:

function isSafeNumber(n) {
    return typeof n === 'number' && isFinite(n);
}

// Or use the replacer function in JSON.stringify
const json = JSON.stringify(data, (key, value) => {
    if (typeof value === 'number' && !isFinite(value)) {
        throw new Error(`Cannot serialize non-finite number at key: "${key}" (value: ${value})`);
    }
    return value;
});

Using a replacer that throws makes the problem visible immediately rather than silently passing null to consumers.

Representing these values in JSON

If you genuinely need to convey NaN or Infinity through JSON, a few patterns are used in practice:

Option 1 — use a string sentinel

{
  "ratio": "NaN",
  "max": "Infinity",
  "min": "-Infinity"
}

The consumer must know to parse these strings back to the appropriate numeric type. Document this convention in your API spec.

Option 2 — use null with a separate flag

{
  "ratio": null,
  "ratio_invalid": true
}

Option 3 — use a large finite sentinel number

Some scientific APIs use 1e308 (near JavaScript's Number.MAX_VALUE) as a stand-in for Infinity. This is fragile and not recommended unless the domain makes it unambiguous.

Parsing JSON that contains these strings

If you receive a JSON string like "NaN" or "Infinity" from a server using the string convention, parse it back in your consumer:

function parseSpecialNumber(value) {
    if (value === 'NaN') return NaN;
    if (value === 'Infinity') return Infinity;
    if (value === '-Infinity') return -Infinity;
    return value;
}

const parsed = JSON.parse(json);
parsed.ratio = parseSpecialNumber(parsed.ratio);

Validating numeric JSON data

If you receive JSON from an external source and want to confirm it contains only finite numbers before processing, paste it into the JSON Validator. A properly formed JSON document will never contain the literal text NaN or Infinity — if you see those tokens outside a string, the source serializer is non-compliant.

Related articles