« Unexpected end of JSON input » — le corps était vide ou tronqué
Cette erreur signifie que le parseur a manqué de texte avant que la structure JSON soit complète. Presque toujours, le corps de la réponse était vide ou le transfert a été tronqué — et les deux cas se corrigent différemment.
Contrairement à la plupart des erreurs JSON, celle-ci ne nomme aucun caractère, parce qu'il n'en restait aucun à nommer. Le parseur a atteint la fin de l'entrée alors qu'il attendait encore une accolade, un crochet ou un guillemet fermant. Votre code de parsing va bien — on vous a remis moins de texte qu'un document JSON complet.
La cause la plus fréquente : le corps était totalement vide
JSON.parse("") lève exactement cette erreur, et une chaîne vide arrive plus souvent qu'on ne le croit. Une réponse 204 No Content n'a pas de corps par définition, ce qui est normal pour un DELETE ou un PUT réussi. Un 304 Not Modified ne renvoie rien non plus, puisque le message est précisément que votre cache reste valide. Une requête HEAD ne renvoie jamais de corps. Et une requête ayant échoué au niveau réseau — connexion refusée, préflight CORS rejeté, requête annulée — peut vous laisser une chaîne vide plutôt qu'une exception, selon le client.
La deuxième cause : la réponse a été tronquée en route
Ici le corps commence comme du JSON valide et s'arrête simplement en chemin. La connexion a été coupée, un timeout s'est déclenché pendant que la réponse était encore en cours, ou quelque chose entre vous et le serveur a imposé une limite de taille — les reverse proxies, les réglages de buffer de nginx et les plafonds de réponse des fonctions serverless font cela silencieusement. Un signal utile : la troncature est souvent intermittente et corrélée à la taille. Les petites réponses passent, les grandes échouent. Si le même endpoint parse bien avec un enregistrement et casse avec mille, il s'agit d'une troncature, pas d'un JSON malformé.
La troisième cause : lecture depuis un stockage ou un fichier
Si le JSON provient de localStorage, d'un fichier de cache ou du disque, c'est peut-être l'écriture qui était incomplète. localStorage échoue silencieusement dès que le quota est dépassé, si bien qu'un gros objet peut être écrit à moitié sans qu'aucune exception ne soit levée à l'écriture — l'erreur n'apparaît que plus tard, à la lecture. Un fichier écrit par un processus qui a planté, ou sur un disque saturé, donne le même résultat. Le signe distinctif : l'échec est rigoureusement identique à chaque fois, alors qu'une troncature réseau est généralement intermittente.
Comment les distinguer en une étape
Avant d'appeler JSON.parse, affichez la longueur de la valeur brute et ses derniers caractères. Une longueur nulle signifie un corps vide : vous devriez traiter le code de statut plutôt que parser. Une longueur non nulle qui ne se termine pas par } ou ] signifie une troncature : comparez alors la longueur reçue à l'en-tête Content-Length. Si la longueur semble complète et que cela échoue quand même, le problème est ailleurs dans la chaîne et le message aurait nommé un caractère.
La correction est une garde, pas un try/catch
Le réflexe est d'entourer le parsing d'un try/catch et de passer à autre chose, mais cela masque la condition réelle et transforme une erreur claire en état vide silencieux. Vérifiez d'abord le code de statut et traitez 204 et 304 explicitement comme « pas de corps, et c'est correct ». Assurez-vous que la réponse a réellement abouti avant de supposer qu'il y a quelque chose à parser. Un try/catch a sa place autour de données réellement inattendues et malformées, pas autour du cas parfaitement prévisible d'une réponse qui n'était jamais censée contenir du JSON.
Quand vous avez le texte brut et voulez savoir exactement où il cesse d'être valide, collez-le dans notre validateur JSON — il indique la position où la structure s'interrompt, ce qui rend une troncature immédiatement visible. Il s'exécute dans votre navigateur, vous pouvez donc coller une vraie réponse d'API sans risque.