⚠️ JavaScript Precision Loss with Large Numbers - The silent bug that breaks applications without error
Source: Dev.to
Imagine this scenario: the backend API returns a perfectly correct number, the Network tab shows the exact value, there are no errors or warnings, yet your frontend logic behaves incorrectly. Hours of debugging later you discover that the value changed automatically.
Welcome to JavaScript precision loss – one of the most dangerous silent bugs in web development.
Why JavaScript loses precision
Numeric type and safe integer range
JavaScript has only one numeric type: Number. Under the hood it uses the IEEE‑754 double‑precision floating‑point format, which can safely represent integers only up to
Number.MAX_SAFE_INTEGER // 9007199254740991 (2^53 - 1)
Any integer greater than this loses precision.
How the bug manifests
Example
{
"transactionId": 9007199254740993
}
The value looks perfect, but once parsed it becomes:
{ transactionId: 9007199254740992 }
9007199254740993 === 9007199254740992 // true
Two different numbers are considered equal, and no error is thrown. This can:
- Break ID‑based logic
- Send wrong IDs in subsequent API calls
- Fail updates/deletes silently
- Corrupt data flows
- Appear only in production, making debugging a nightmare
The precision loss occurs during JSON.parse(), which converts JSON numbers directly into Number.
Detecting precision loss
- Open Network → Response and compare with Network → Preview.
- Log the raw response text before parsing.
- Compare values using strict equality (
===). - Check whether any numeric field exceeds
Number.MAX_SAFE_INTEGER.
If you see discrepancies, you’re likely dealing with a precision issue.
Fixing the issue
Return large identifiers as strings
{
"transactionId": "9007199254740993"
}
Stringifying the number prevents any loss of precision on the client side.
Using json-bigint for legacy or third‑party APIs
json-bigint parses JSON without losing precision.
npm install json-bigint
import JSONbig from 'json-bigint';
const response = JSONbig.parse(apiResponseText);
// Large numbers are preserved as BigInt (or string, depending on options)
You can then choose how to handle the values:
- Keep them as
BigInt - Convert to strings for transport
- Apply custom handling logic
Remember to convert them back to a suitable format before sending data to other APIs.
Best practices
- Treat IDs as identifiers, not numbers – avoid arithmetic on them.
- Consistently use strings or
BigIntfor any value that may exceed2^53 - 1. - Document API contracts to specify that large numeric fields must be serialized as strings.
- Validate incoming data on both client and server sides against
Number.MAX_SAFE_INTEGER.
By respecting JavaScript’s numeric limits, you eliminate a class of silent, production‑only bugs.
If this post helped you learn something new, you’re already ahead of many developers.
Have you ever faced a bug where everything “looked correct” but wasn’t? Drop your experience in the comments – let’s learn from each other.