Why big numbers in JSON change their last digits

This is not a syntax error: the JSON is valid, and the damage happens silently when it is parsed. JavaScript stores every number as a 64-bit float, which holds integers exactly only up to 2^53 (9,007,199,254,740,991). Larger values, typical for database IDs and Twitter or Discord snowflakes, are rounded to the nearest representable number. PasteKit keeps number text exactly as written, so this sample formats unchanged here while JSON.parse would alter both IDs.

Seen as:

  • TypeError: Do not know how to serialize a BigInt
  • json: cannot unmarshal number 12345678901234567890 into Go struct field Order.orderId of type int64
  • This number literal will lose precision at runtime.
  • 1234567890123456789 → 1234567890123456800

Input

Settings

History

Load from URL

Common causes

1. 64-bit IDs sent as JSON numbers

BIGINT primary keys, snowflake IDs and payment references routinely exceed 2^53. Send them as strings; an ID is never used for arithmetic anyway.

Before
{"orderId": 1234567890123456789}
After
{"orderId": "1234567890123456789"}

2. Parsing in JavaScript without a reviver

When you cannot change the producer, read the original digits. Modern engines (Chrome 114+, Node 21+) pass the source text to the reviver, so large integers can become BigInt.

Before
const order = JSON.parse(text);
After
const order = JSON.parse(text, (key, value, context) =>
  typeof value === 'number' && !Number.isSafeInteger(value) && /^-?\d+$/.test(context.source)
    ? BigInt(context.source)
    : value,
);

3. Serializing BigInt values

Once you hold a BigInt, JSON.stringify throws “Do not know how to serialize a BigInt”. Convert it explicitly, usually to a string.

Before
const body = JSON.stringify({ orderId: 1234567890123456789n });
After
const body = JSON.stringify({ orderId: 1234567890123456789n }, (key, value) =>
  typeof value === 'bigint' ? value.toString() : value,
);

4. Decimal amounts and trailing zeros

Floats also drop formatting: 129.90 parses to 129.9, and values with more than about 15 significant digits are rounded. For money, send integer minor units or a decimal string.

Before
{"total": 129.90, "rate": 0.1234567890123456789}
After
{"totalCents": 12990, "rate": "0.1234567890123456789"}

Frequently asked questions

What is the largest safe integer in JSON?

JSON itself has no limit, but JavaScript and many other parsers use 64-bit floats, which are exact up to 9,007,199,254,740,991 (Number.MAX_SAFE_INTEGER). Treat anything larger as unsafe unless every consumer uses a big-number parser.

Does Python lose precision too?

No for integers: Python’s json module parses them as arbitrary-size int. Floats still become 64-bit doubles unless you pass parse_float=decimal.Decimal.

Will PasteKit change my numbers when formatting?

No. The formatter copies number text exactly, so 1234567890123456789 and 129.90 come out as written. Conversions such as JSON to YAML or CSV also keep the original digits.

Related