Pourquoi les grands entiers perdent de la précision
L’essentiel : Les entiers au-delà de 2^53-1 perdent de la précision dans JSON.parse. Les identifiants snowflake, numéros de commande et bigints de base de données y sont tous exposés, donc gardez-les en chaînes de bout en bout.

L'essentiel : traitez les identifiants snowflake, numéros de commande et clés primaires bigint comme des chaînes tout au long de la sérialisation, du transport et du parsing ; ne gardez le type numérique que lorsque le champ est prouvé rester dans 2^53-1, et imposez-le alors avec une contrainte maximum dans le Schema.
Parce que les dégâts se produisent pendant le parsing, silencieusement.
JSON.parse('{"id": 9007199254740993}');
// { id: 9007199254740992 }
Le chiffre manquant a disparu ; il n'y a rien à récupérer.
D'où vient 2^53
JavaScript n'a qu'un type numérique : le double précision IEEE 754, avec 53 bits de mantisse (un implicite, 52 explicites). Les entiers exacts s'arrêtent donc à ±(2^53-1) :
-9007199254740991 .. 9007199254740991
Au-delà de cette ligne, les valeurs représentables consécutives sont espacées de 2, 4, 8. 9007199254740993 est impair, et à cette magnitude chaque valeur représentable est paire, donc il s'arrondit à 9007199254740992.
Les champs touchés
| Champ | Chiffres | Risque |
|---|---|---|
| Identifiants snowflake | 18 à 19 | Élevé, les derniers chiffres changent |
| Numéros de commande / transaction | 16 à 20 | Élevé |
| Clés primaires bigint de base de données | 19 | Élevé |
| Argent en unités mineures | — | Faible |
| Horodatages en millisecondes | 13 | Sûr |
Le fil conducteur : ce sont des identifiants, pas des quantités. Un identifiant est transporté, jamais additionné ni multiplié, donc la chaîne est le bon type.
Quatre corrections
Sérialisez en chaîne. Le backend convertit les champs bigint avant d'écrire la réponse. Simple et durable ; documentez que ces champs sont des chaînes.
Laissez le sérialiseur s'en charger. Le ToStringSerializer de Jackson pour Long, le tag json:",string" de Go. Même idée : garder la valeur hors du chemin numérique.
Parsez avec le support BigInt. json-bigint et bibliothèques similaires. Notez que BigInt ne peut pas se mélanger à l'arithmétique Number, et que JSON.stringify le rejette.
Contraignez la plage. Si le champ ne peut réellement pas dépasser 2^53, ajoutez maximum dans le Schema pour que les données hors plage échouent à la validation au lieu d'échouer silencieusement dans le navigateur.
Comment savoir si vous avez ce bug
Prenez un identifiant connu et faites-lui un aller-retour : sérialisez, transmettez, parsez, comparez caractère par caractère. Ou inspectez le corps de réponse brut — un nombre non cité de 19 chiffres qui arrive avec les mauvais derniers chiffres est presque certainement une perte au parsing.
FAQ
Pourquoi JSON.parse change-t-il les derniers chiffres sans erreur ?
JavaScript n'a qu'un type numérique, le double précision IEEE 754, donc les entiers au-delà de 2^53-1 ne peuvent atterrir que sur la valeur représentable la plus proche. JSON.parse traite cela comme une conversion numérique normale : ni exception ni avertissement.
Comment le frontend peut-il garder les grands entiers intacts ?
Utilisez une bibliothèque comme json-bigint, car JSON.parse ne peut pas le faire. Le coût est que BigInt ne peut pas se mélanger à l'arithmétique Number et que JSON.stringify le rejette, donc le code environnant doit aussi changer.
La doc d'API doit-elle préciser que ces champs sont des chaînes ?
Oui. Sérialiser en chaînes est la correction la plus simple et la plus durable, mais elle ne fonctionne que si les consommateurs traitent la valeur comme du texte, donc le type de champ doit être écrit dans le contrat d'API.