Skip to content

parse_constant receives '-NaN', breaking json-module-style hooks #152

Open

Description

@rahul05ranjan

A parse_constant hook written to the json module's contract breaks on -NaN, because pyjson5 passes the signed spelling to the hook instead of normalizing it:

import json5

HOOK = {'NaN': 'nan', 'Infinity': 'inf', '-Infinity': '-inf'}.__getitem__

json5.loads('NaN', parse_constant=HOOK)         # ok
json5.loads('-Infinity', parse_constant=HOOK)   # ok
json5.loads('-NaN', parse_constant=HOOK)        # KeyError: '-NaN'

json's documented contract only ever passes 'NaN', 'Infinity', or '-Infinity' to parse_constant, so code written against it assumes a closed set. -NaN is legal JSON5, so this is reachable with perfectly ordinary input.

The inconsistency is especially visible next to the + spelling, which already arrives normalized (the parser drops the plus sign):

json5.loads('+NaN', parse_constant=HOOK)  # ok — hook receives 'NaN'

Two possible resolutions:

  • normalize like the default parser does (_fp_constant_parser already handles -NaN via float('-nan')), so hooks receive 'NaN' for both NaN and -NaN, or
  • keep passing the literal but document it next to the existing parse_int caveat in the load/loads/parse docstrings (the docstrings already warn that parse_int sees 0x… spellings).

The first keeps drop-in compatibility with json-shaped hooks, which I suspect is worth more given the library already mirrors json's API so closely.

Activity

  1. dpranke commented on Nov 2, 2026

    @dpranke
    Owner

    Actually, I think the second resolution is better. A parse_constant hook should have to accept -NaN since it is legal JSON5.

    I.e., I think the code is correct but the documentation is buggy and should be fixed.

  2. rahul05ranjan commented on Nov 2, 2026

    @rahul05ranjan
    ContributorAuthor

    Agreed — since -NaN is legal JSON5 and the hook sees the spelling as written, documenting the contract (rather than normalizing) keeps the parser lossless. I've sent #157 with the docstring updates: a parse_constant bullet next to the existing parse_int caveat in load()/loads(), and the lettered list in parse() extended to match. Docstrings only, no behavior changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions