← All tools

Tested guide

Why JSON formatting can change large numbers

A reproducible example of a 17-digit ID changing during parsing, and when to use a string.

By URNPC · Published and tested October 1, 2026

JSON syntax permits large numbers, but JavaScript parses ordinary JSON numbers into binary64 Number values. An integer outside ±9,007,199,254,740,991 is outside the safe integer range. Its digits can change before formatting even begins. Keep identifiers as strings when the data contract allows it.

The experiment

Measured examples · 2026-10-01
What we testedInput textNative parse → stringify
An integer beyond the safe range{"id":9007199254740993}{"id":9007199254740992}
The same identifier stored as a string{"id":"9007199254740993"}{"id":"9007199254740993"}
Trailing decimal zeroes{"price":1.2300}{"price":1.23}

Computed from the published fixtures using Node.js 22.22.2, ICU 78.2, Unicode 17.0. Run the same examples in your browser.

The change happens during parsing

The first test below starts with the literal 9007199254740993. JSON.parse reads it as 9007199254740992; JSON.stringify then prints that already-rounded value. Indentation is not the cause. The number was converted into a representation that cannot distinguish those adjacent integers.

The safe range is a guarantee about consecutive integers. Some integers outside that range are exactly representable, but their neighbours may not be. A successful parse therefore does not establish that the original digits survived.

Choose a representation before processing

For an order ID, account reference or other value that is never used for arithmetic, a string often matches the meaning better. This works only if both producer and consumer agree. Changing a numeric field to a string can break schema validation or an existing API.

For exact financial quantities or arbitrary-precision calculations, choose a parser and numeric representation designed for that contract. Quoting the result after a normal parse cannot recover digits that were already lost. Keep the original text.

What our formatter checks

URNPC refuses integer literals outside the safe range and non-finite numeric conversions. It uses native JSON.parse and JSON.stringify after these checks. Decimals and exponent notation still follow binary64 rounding; this is not an arbitrary-precision or lossless formatter.

The decimal example also shows 1.2300 becoming 1.23. These spellings represent the same number, but different text. Do not round-trip a signed document or a byte-exact payload through this tool. Try the quoted-ID example in the formatter to keep its digits.

Standards and references

These results describe the tested implementations and inputs. Report a reproducible discrepancy through our contact page.

Continue exploring