Which languages silently corrupt large JSON numbers
The same JSON document, parsed and re-serialised by 11 parsers across 10 runtimes. No errors are raised anywhere below — the values simply come back different.
A 64-bit ID does not survive every parser
JSON's grammar permits arbitrary-precision numbers. Most parsers map them onto an IEEE 754 double, which represents integers exactly only up to 253−1. Above that the value is rounded, silently, with no error and no warning.
Of the 11 parsers measured, 4 lose precision on a 64-bit integer: JavaScriptCore JSON.parse, SpiderMonkey JSON.parse, V8 JSON.parse, encoding/json Unmarshal.
{"v":1541815603606036480} — a real Snowflake ID — comes back as 1541815603606036500 in every JavaScript engine and in Go. The last two digits are gone, and nothing tells you.
Four number probes across every parser
| Parser | 263−1 | Snowflake ID | 30 decimal places | 1.0 |
|---|---|---|---|---|
| CPython json.loads | {"v": 9223372036854775807} | {"v": 1541815603606036480} | {"v": 3.141592653589793} | {"v": 1.0} |
| Gson | {"v":9223372036854775807} | {"v":1541815603606036480} | {"v":3.141592653589793238462643383 | {"v":1.0} |
| Jackson ObjectMapper | {"v":9223372036854775807} | {"v":1541815603606036480} | {"v":3.141592653589793} | {"v":1.0} |
| JavaScriptCore JSON.parse | {"v":9223372036854776000} | {"v":1541815603606036500} | {"v":3.141592653589793} | {"v":1} |
| Newtonsoft.Json | {"v":9223372036854775807} | {"v":1541815603606036480} | {"v":3.141592653589793} | {"v":1.0} |
| Ruby JSON.parse | {"v":9223372036854775807} | {"v":1541815603606036480} | {"v":3.141592653589793} | {"v":1.0} |
| SpiderMonkey JSON.parse | {"v":9223372036854776000} | {"v":1541815603606036500} | {"v":3.141592653589793} | {"v":1} |
| System.Text.Json | {"v":9223372036854775807} | {"v":1541815603606036480} | {"v":3.141592653589793238462643383 | {"v":1.0} |
| V8 JSON.parse | {"v":9223372036854776000} | {"v":1541815603606036500} | {"v":3.141592653589793} | {"v":1} |
| encoding/json Unmarshal | {"v":9223372036854776000} | {"v":1541815603606036500} | {"v":3.141592653589793} | {"v":1} |
| json_decode | {"v":9223372036854775807} | {"v":1541815603606036480} | {"v":3.141592653589793} | {"v":1} |
Green means the literal survived the round trip. Red means it changed.
One input, seven different outcomes
The probe {"v":1e400} — an exponent beyond the float64 range — is where agreement collapses completely:
| Result | Parsers |
|---|---|
{"v":null} | JavaScriptCore JSON.parse, SpiderMonkey JSON.parse, V8 JSON.parse |
{"v":"Infinity"} | Jackson ObjectMapper, Newtonsoft.Json |
{"v":1e400} | Gson, System.Text.Json |
False | json_decode |
{"v": Infinity} | CPython json.loads |
Infinity not allowed in JSON | Ruby JSON.parse |
json: cannot unmarshal number 1e400 into Go va | encoding/json Unmarshal |
Practical rules
Transport large identifiers as strings. If an ID can exceed 253−1, it is an identifier, not a quantity, and belongs in a string. This is why Twitter's API has always returned both id and id_str.
If you cannot change the producer, use a parser that preserves precision: json-bigint in JavaScript, parse_int= in Python's json.loads, json.Number with a Decoder in Go.
Test with a value above 9007199254740991. Anything smaller passes everywhere and tells you nothing.
Standards referenced
RFC 8259 §6 names 1E400 and 3.141592653589793238462643383279 as its own examples of numbers that signal interoperability problems — both are probes in this dataset.
- RFC 8259 (STD 90) §6 — Numbers — The JavaScript Object Notation (JSON) Data Interchange Format, T. Bray, Ed., 2017.
- IEEE 754-2019 — IEEE Standard for Floating-Point Arithmetic, IEEE, 2019.
- ECMA-404, 2nd edition §numbers — 8 Numbers — The JSON Data Interchange Syntax, Ecma International, 2017.
Peer-reviewed literature
- D. Goldberg, “What every computer scientist should know about floating-point arithmetic”, ACM Computing Surveys, vol. 23, no. 1, pp. 5–48, 1991. doi:10.1145/103162.103163
- W. D. Clinger, “How to read floating point numbers accurately”, Proc. ACM SIGPLAN Conf. on Programming Language Design and Implementation (PLDI ’90), 1990. doi:10.1145/93542.93557
- G. L. Steele Jr. and J. L. White, “How to print floating-point numbers accurately”, Proc. ACM SIGPLAN Conf. on Programming Language Design and Implementation (PLDI ’90), 1990. doi:10.1145/93542.93559
- D. Lemire, “Number parsing at a gigabyte per second”, Software: Practice and Experience, vol. 51, no. 8, pp. 1700–1727, 2021. doi:10.1002/spe.2984
Only standards bodies and peer-reviewed venues are cited here.
How this was measured
Each probe was passed to every parser, the result re-serialised, and the output recorded verbatim. 165 observations in total. Re-serialising rather than inspecting in-memory values makes results comparable across languages that have different numeric types.
Every figure on this page came from executing the parser named, not from documentation. The collection harness is public — see the error registry method notes.