I gave 24 awkward JSON documents to 6 parsers. Five behaved the same everywhere.
JSON is the format everyone agrees on. So I wrote 24 awkward but small documents, fed the identical bytes to six parsers on one laptop, and compared what came back. Five of the 24 behaved the same way everywhere. Three parsed to the same value and two were rejected by all six. The other 19 produced divergence : either some parsers accepted a document that others refused, or they all accepted it…
JSON is a universally accepted format for data exchange. In a test, 24 small JSON documents were fed to six parsers on a single laptop, and 5 of the 24 behaved consistently across all parsers. However, 19 produced inconsistent results - some parsers accepted a document while others rejected it, or they all accepted it but disagreed on its meaning. The parsers tested were Python 3.13 json, Node 24 JSON.parse, Ruby 2.6 json, Perl JSON::PP, jq 1.8.1, and Swift 6.3 JSONSerialization.
The issue primarily revolves around the uniqueness of object keys, which RFC 8259 suggests should be unique but does not specify the behavior when they are not. Five parsers agreed on the value { a :2}, while Swift returned { a :1}. This discrepancy can cause significant problems, such as a gateway validating one set of keys while the backend reads a different set.
Another issue is with the representation of large numbers. Python, Ruby, Perl, jq, and Swift all return the exact number { n :12345678901234567890}, while Node returns 12345678901234567000. This discrepancy occurs due to the way JavaScript handles large integers, causing data corruption in transit.
The test also revealed differences in handling special values like Infinity, NaN, and numbers exceeding the 64-bit integer limit. While Python, Ruby, Perl, jq, and Swift accurately handled these cases, Node returned null for Infinity and an approximate value for numbers exceeding the 64-bit limit.
Three documents parsed consistently across all parsers: an empty key, an escaped NUL, and an object with a special key "__proto__". Two documents were rejected by all parsers: a string with a raw tab character and single-quoted keys. Despite these inconsistencies, there was unanimous agreement on the handling of certain edge cases.
To prevent issues, it is recommended to avoid duplicate keys and send large integers as strings. This practice is crucial to avoid silent loss of data, as JavaScript's handling of large integers can lead to significant errors in downstream systems.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.