What even is a JSON number?

JSON’s treatment of numbers—especially how they map (or fail to map) to IEEE 754 double-precision floats—raises subtle but serious interoperability problems, from silent rounding of large integers to inconsistent handling of decimals across languages and libraries. Commenters compare strategies such as treating numbers as strings, using decimal or big-integer types, or scaling values into integers, and note that many standard JSON parsers either lose precision or even mis-round edge cases by default. The conversation repeatedly returns to money and identifiers as domains where these quirks can become catastrophic, reinforcing the need for explicit schemas, careful type choices, and sometimes alternative formats when exact numeric behavior matters.

JSON numbers vs IEEE-754 and I‑JSON

  • Thread centers on how JSON’s “number” maps to IEEE 754 double precision and I‑JSON’s recommendation not to exceed that magnitude/precision.
  • Confusion over how to define “precision” of literals like 0.1 that cannot be represented exactly.
  • One interpretation: the message should not imply more precision than a double can store; short forms like 0.1 are fine, but very long decimal expansions are misleading.

Language behavior and parser customization

  • Many standard JSON libraries default to IEEE‑754 doubles and silently lose digits.
  • Several languages offer hooks to avoid this:
    • Go UseNumber to keep numeric strings.
    • Python parse_int / parse_float to map to Decimal or str.
    • JavaScript is gaining JSON.parse “with source” (context) to reconstruct BigInt or custom types, but support is still incomplete across engines.
  • Some recommend using validation/parsing layers (e.g., schema libraries) to coerce JSON numbers into safer internal types.

Integers, IDs, and “safe” ranges

  • Multiple anecdotes of 64‑bit identifiers breaking when parsed as JS numbers (precision loss around 2^53).
  • Advice: treat IDs as strings in JSON, even if they are integers in databases.
  • Counterpoint from data/analytics side: integer keys are significantly faster than strings in large joins, at least inside databases.

Money, decimals, and fixed‑point

  • Strong consensus: don’t use JSON binary floats for money.
  • Strategies:
    • Scale to integers (cents, mills, millicents) and encode as JSON numbers, but this bakes in assumptions about precision and can conflict with varying currency rules and changing standards.
    • Store as DECIMAL/BigDecimal in DB and serialize as decimal strings in JSON; let domain logic handle rounding rules.
    • Use explicit “money” value objects instead of raw numeric types.

Arbitrary precision, DoS, and limits

  • Some libraries (e.g., Haskell’s Scientific, Rust BigDecimal) parse into arbitrary-precision types.
  • Concern: untrusted JSON can contain huge exponents or thousands of digits, and naive arithmetic can exhaust memory (potential DoS).
  • Proposed mitigations: hard or configurable precision/size limits, separate “huge” vs “normal” numeric types, or failing parsers on oversized numbers.

Spec design, NaN/Inf, and alternatives

  • JSON explicitly allows implementations to limit precision; many see this as a fundamental interoperability flaw.
  • Lack of NaN/Inf representation forces ad‑hoc handling; some languages serialize them anyway, breaking strict JSON.
  • Alternatives mentioned: Mongo Extended JSON, Amazon Ion, XML with schemas; these offer richer, better‑specified numeric types but less ubiquity than plain JSON.