Browser JSON.parse Precision Loss with Nanosecond Timestamps
A Python server sending nanosecond modification timestamps as JSON to a Node.js v22.23.2 browser encounters precision loss past MAX_SAFE_INTEGER, causing backend file check failures.

Stock photo for illustration only, not from the actual event
- A Python server lists video clips with modification times in nanoseconds via JSON.
- Large numbers exceed MAX_SAFE_INTEGER, causing rounding errors in browser JSON.parse.
- Newer features like the source argument in JSON.parse reviver offer a reliable audit trail.
- Alternative fixes include string serialization or dropping precision down to milliseconds.
Data precision issues in software engineering can stem from subtle architectural boundaries. A recent test case conducted on a Linux machine running kernel 6.8, Python 3.10.12, and Node.js v22.23.2 highlights how precision limits can disrupt file verification workflows. The setup involved a small Python server serving a folder clip list as JSON, storing each file's modification timestamp in nanoseconds.
The frontend browser reading this list determined that two out of three files shared the exact same timestamp. To test this, a script created three empty files with modification times set precisely 100 nanoseconds apart using os.utime(ns=...) to guarantee consistent behavior across runs. Problems arose when the browser sent a timestamp back to verify if the file had changed; the server incorrectly flagged it as modified even though no changes occurred. The numbers were simply too massive for JSON.parse to retain their exact values.
In this context, safety refers to the system's ability to represent integers precisely and compare them without error. A nanosecond timestamp generated this year is roughly two hundred times larger than the safe integer threshold, and Python's math.ulp function can evaluate the precise distance between neighboring double-precision values at that magnitude.

Stock photo for illustration only, not from the actual event
When the browser requests an action on a file like c.mp4 only if it remains unchanged, returning the stored timestamp triggers a mismatch. Files a.mp4 and b.mp4 end up holding identical values on the client side, rendering newer-than tests ineffective at distinguishing between them.
Technically, this limitation stems from JavaScript relying on 64-bit floating-point numbers (IEEE 754), which safely represent integers up to 2^53 - 1, known as Number.MAX_SAFE_INTEGER (9,007,199,254,740,991). When nanosecond timestamps span 19 digits or more, the trailing digits are automatically rounded off during JSON parsing, causing client and server states to drift apart despite flawless underlying logic.
Documentation from MDN regarding JSON.parse explains that the reviver function executes after parsing concludes, meaning numerical values in JSON strings have already been converted into standard JavaScript numbers and may lose precision during conversion.
Fortunately, Node 22 implements the third argument of the reviver function, exposing a source field containing the raw text representation of the value. This enables a lightweight audit by comparing the source text against parsed output, utilizing patterns like BigInt(context.source) to rebuild integers accurately.
Beyond reviver adjustments, alternative engineering patterns include:
- Serializing the field as a string, allowing safe passage across any legacy or modern JSON parser.
- Dividing by one million to drop timestamps down to whole milliseconds, placing values comfortably below the safe threshold.
However, reducing precision to milliseconds carries trade-offs. If a file is rewritten within the same millisecond window, change-detection checks will fail to notice. For strict synchronization requirements, utilizing a content hash or a version counter transmitted as a string remains the recommended practice.
Source: Dev.to
Found something wrong in this article? Report an issue with this article
Comments
Leave a Comment