Skip to content

Commit 3fc6f4d

Browse files
Add explanation that explains why JSON strings for int64s
PiperOrigin-RevId: 868786771
1 parent 8f18fc9 commit 3fc6f4d

1 file changed

Lines changed: 37 additions & 4 deletions

File tree

content/programming-guides/json.md

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ The following table shows how data is represented in JSON files.
7474
<p>
7575
Well-known types have special representations, as described in the <a href="#wkt">Well-known types table</a>.
7676
<p>
77-
<code>null</code> is valid for any field and leaves the field unset. See <a href="null-values">Null Values</a> for clarification about the semantic behavior of null values.
77+
<code>null</code> is valid for any field and leaves the field unset. See <a href="#null-values">Null Values</a> for clarification about the semantic behavior of null values.
7878
</td>
7979
</tr>
8080
<tr>
@@ -122,7 +122,7 @@ The following table shows how data is represented in JSON files.
122122
<td>int32, fixed32, uint32</td>
123123
<td>number</td>
124124
<td><code>1, -10, 0</code></td>
125-
<td>JSON value will be a decimal number. Either numbers or strings are
125+
<td>JSON value will be a number. Either numbers or strings are
126126
accepted. Empty strings are invalid. Exponent notation (such as <code>1e2</code>) is
127127
accepted in both quoted and unquoted forms.
128128
</td>
@@ -133,7 +133,8 @@ The following table shows how data is represented in JSON files.
133133
<td><code>"1", "-10"</code></td>
134134
<td>JSON value will be a decimal string. Either numbers or strings are
135135
accepted. Empty strings are invalid. Exponent notation (such as <code>1e2</code>) is
136-
accepted in both quoted and unquoted forms.
136+
accepted in both quoted and unquoted forms. See <a href="#int64-strings">Strings for int64s</a>
137+
for the explanation why strings are used for int64s.
137138
</td>
138139
</tr>
139140
<tr>
@@ -314,7 +315,7 @@ may be impractical or infeasible, so it is strongly recommended that systems
314315
avoid relying on specific behavior for duplicate fields in ProtoJSON where
315316
possible.
316317

317-
### Out of range numeric values
318+
### Out of range numeric values {#out-of-range-values}
318319

319320
When parsing a numeric value, if the number that is is parsed from the wire
320321
doesn't fit in the corresponding type, the parser should fail to parse.
@@ -326,6 +327,38 @@ Values with nonzero fractional portions are not allowed for integer-typed
326327
fields. Zero fractional portions are accepted. For example `1.0` is valid for an
327328
int32 field, but `1.5` is not.
328329

330+
### Strings for int64 {#int64-strings}
331+
332+
Unfortunately, the [json.org](https://json.org) spec does not speak to the
333+
intended precision limits of numbers. Many implementations follow the original
334+
JS behavior that JSON was derived from and interpret all numbers as binary64
335+
(double precision) and are silently lossy if a number is an integer larger than
336+
2**53. Other implementations may support unlimited precision bigints, int64s, or
337+
even bigfloats with unlimited fractional precision.
338+
339+
This creates a situation where if the JSON contains a number that is not exactly
340+
representable by double precision, different parsers will behave differently,
341+
including silent precision loss in many languages.
342+
343+
To avoid these problems, ProtoJSON serializers emit int64s as strings to ensure
344+
no precision loss will occur on large int64s by any implementation.
345+
346+
When parsing a bare number when expecting an int64, the implementation should
347+
coerce that value to double-precision even if the corresponding language's
348+
built-in JSON parser supports parsing of JSON numbers as bigints. This ensures a
349+
consistent interpretation of the same data, regardless of language used.
350+
351+
This design follows established best practices in how to handle large numbers in
352+
JSON when prioritizing interoperability, including:
353+
354+
* [RFC8259](https://datatracker.ietf.org/doc/html/rfc8259#section-6) includes
355+
a note that software that intends good interoperability should only presume
356+
double precision on all numbers.
357+
358+
* [OpenAPI int64](https://spec.openapis.org/registry/format/int64)
359+
documentation recommends using a JSON string instead of a number when
360+
precision beyond 2**53 is desired.
361+
329362
## Any {#any}
330363

331364
### Normal messages {#any-normal-messages}

0 commit comments

Comments
 (0)