Urgent.News

What's breaking now, across thousands of outlets.

Tech

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.

Read the original at dev.to →

More in Tech

iraca: independent differential verification of ML-KEM (FIPS 203) in RustCrypto

Qué hicimos iraca es un arnés que verifica la criptografía post-cuántica que el ecosistema Rust realmente usa, diferenciándola contra una implementación independiente .

  • IRACA developed harness to verify ML-KEM (FIPS 203) in RustCrypto
  • RustCrypto crate ml-kem identical to pq-crystals reference in key generation
  • IRACA's method ensures functional differential testing with 128 seeds

Async LINQ: Why ToListAsync Exists (And Why WhereAsync Doesn't)

Async LINQ: Why ToListAsync Exists (And Why WhereAsync Doesn't) You write await dbContext.Products.ToListAsync() . Good. Then you wonder: where's WhereAsync ?

  • ToListAsync exists to execute LINQ queries asynchronously at terminal operators.
  • WhereAsync doesn't exist because Where operator doesn't interact with the database.
  • Entity Framework Core provides async versions of execution-triggering operators.

More from Monday 28 September →