Skip to content

jsonify emits NaN and Infinity, which are not valid JSON #6114

Description

@PranavAchar01

jsonify serialises float("nan") and float("inf") as the bare literals NaN and Infinity. Those are not valid JSON (RFC 8259 allows only decimal numbers), so the response is served as application/json but cannot be parsed by a strict parser, including the browser's JSON.parse.

This inherits from json.dumps, whose allow_nan defaults to True. DefaultJSONProvider sets default, ensure_ascii and sort_keys, but never touches allow_nan, so the permissive default applies.

The path to it is ordinary: any average, ratio or division that can meet an empty input produces nan without anything looking wrong on the server.

Replication:

from flask import Flask, jsonify

app = Flask(__name__)

@app.route("/stats")
def stats():
    values = []
    mean = sum(values) / len(values) if values else float("nan")
    return jsonify({"count": len(values), "mean": mean})

with app.test_client() as c:
    r = c.get("/stats")
    print(r.headers["Content-Type"])      # application/json
    print(r.get_data(as_text=True))       # {"count":0,"mean":NaN}

The response advertises application/json with a 200, but the body is not JSON:

import json
json.loads('{"count":0,"mean":NaN}')      # accepted, Python is permissive by default
json.loads('{"count":0,"mean":NaN}',
           parse_constant=lambda x: (_ for _ in ()).throw(ValueError(x)))
# ValueError: NaN     <- what a strict parser, and JSON.parse in a browser, does

So the failure surfaces in the client rather than the server, which makes it awkward to trace back.

Expected: either the same behaviour with it documented, or serialisation raises so the problem shows up server-side, where ValueError: Out of range float values are not JSON compliant: nan names the cause immediately.

There is currently no class attribute for this, although the plumbing already works, since dumps forwards **kwargs to json.dumps:

app.json.dumps({"a": float("nan")}, allow_nan=False)
# ValueError: Out of range float values are not JSON compliant: nan

DefaultJSONProvider exposes sort_keys, ensure_ascii and compact as class attributes, so an allow_nan attribute alongside them would fit the existing pattern and let applications choose, without changing the default for anyone. I could not find NaN mentioned in the DefaultJSONProvider or flask.json.dumps docstrings, so at minimum a documentation note seems worthwhile.

Happy to send a PR for whichever you prefer, an allow_nan provider attribute or just the docs.

Environment:

  • Python 3.14
  • Flask 3.1.3
  • Werkzeug 3.1.8

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions