Unexpected token in JSON : ce que signifie l'erreur et comment la corriger
Cette erreur signifie que le texte analysé n'est pas du JSON. Le token cité indique en général ce que vous avez reçu à la place.
Vous appelez JSON.parse() ou response.json() et, au lieu des données, vous obtenez une SyntaxError. Le libellé varie selon le navigateur, mais le sens reste le même : l'analyseur a lu le texte depuis le début et il est tombé sur un caractère qui ne peut pas figurer à cet endroit dans un JSON valide. Le caractère cité et sa position sont les indices les plus précieux dont vous disposez.
La même erreur selon le moteur
Les versions récentes de Chrome et de Node.js ont changé la formulation : vous trouverez donc les deux variantes dans les résultats de recherche et dans les anciens journaux.
| Où elle apparaît | Message |
|---|---|
| Chrome, Edge, Node.js 20 et versions suivantes | Unexpected token '<', "<!DOCTYPE "... is not valid JSON |
| Anciennes versions de Chrome, Node.js 18 | Unexpected token < in JSON at position 0 |
| Firefox | JSON.parse: unexpected character at line 1 column 1 of the JSON data |
| Safari | JSON Parse error: Unrecognized token '<' |
« position 0 » ou « line 1 column 1 » signifie que le tout premier caractère était déjà incorrect. Presque toujours, cela indique que la réponse n'est pas du JSON du tout, et non qu'une petite faute de frappe s'est glissée dans un document JSON.
La cause habituelle : une page HTML au lieu du JSON
Un < inattendu en position 0 est de loin la variante la plus fréquente. Le code a demandé du JSON à une API, mais le serveur a répondu par une page HTML, et une page HTML commence par <!DOCTYPE html> ou <html>. Les raisons typiques :
- Une URL erronée : une faute de frappe ou un préfixe
/apioublié renvoie la page 404 du site. - Une erreur serveur : le framework affiche une page d'erreur 500 en HTML.
- Une session expirée : la requête est redirigée vers une page de connexion, et
fetchsuit la redirection sans rien signaler. - Le fallback d'une single-page app : le serveur de développement ou l'hébergeur renvoie
index.htmlpour tout chemin inconnu, avec un statut 200. - Un proxy, un CDN ou un pare-feu placé entre les deux envoie sa propre page HTML d'erreur ou de vérification.
Le moyen le plus rapide de le confirmer consiste à examiner la réponse brute avant de l'analyser :
const res = await fetch('/api/items');
console.log(res.status, res.headers.get('content-type'));
const text = await res.text();
console.log(text.slice(0, 200)); // affiche le HTML si c'est bien ce qui est revenu
Dans le navigateur, vous pouvez aussi ouvrir le panneau Réseau (Network) des outils de développement, cliquer sur la requête et consulter l'onglet Réponse (Response). Si vous y voyez du HTML, corrigez l'URL, l'authentification ou l'erreur serveur : le code d'analyse, lui, est correct.
Les autres tokens et ce qu'ils révèlent
| Message actuel (ancien message) | Ce que vous avez analysé | Correction |
|---|---|---|
"undefined" is not valid JSON (Unexpected token u in JSON at position 0) | La valeur undefined, par exemple une clé localStorage absente ou une variable non définie | Vérifier que la valeur existe avant de l'analyser |
"[object Object]" is not valid JSON (Unexpected token o in JSON at position 1) | Un objet déjà analysé, converti en chaîne par JSON.parse | Utiliser l'objet directement, sans l'analyser une seconde fois |
Expected property name or '}' in JSON at position 1 | Des guillemets simples ou des clés sans guillemets, comme dans {'a': 1} ou {a: 1} | Mettre des guillemets doubles autour de chaque clé et de chaque chaîne |
Expected double-quoted property name in JSON at position 8 | Une virgule finale, comme dans {"a": 1,} | Supprimer la virgule avant l'accolade fermante |
Unexpected token 'N', "{"a": NaN}" is not valid JSON | NaN, Infinity ou undefined dans les données | Les remplacer par null ou par un nombre |
| Un message qui cite un token invisible ou apparemment vide en position 0 | Une marque d'ordre des octets (BOM) au début d'un fichier enregistré par certains éditeurs Windows | Enregistrer le fichier en UTF-8 sans BOM, ou supprimer le premier caractère |
Analyser des données déjà analysées
Les bibliothèques vous livrent souvent des objets tout prêts. response.json() renvoie déjà un objet JavaScript, tout comme axios dans response.data. Passer cet objet à JSON.parse le convertit d'abord en chaîne "[object Object]", ce qui échoue en position 1. Supprimez l'analyse en trop :
const data = await res.json();
// JSON.parse(data) <- échoue : data est déjà un objet
console.log(data.items);
Trouver l'erreur dans un vrai JSON
Quand la position indiquée se situe quelque part au milieu, le texte est bien du JSON, mais il contient une erreur. Collez-le dans le validateur JSON : il utilise le même analyseur que votre navigateur, affiche le message avec la position et la ligne, et formate le document dès qu'il est valide. La véritable erreur se trouve en général juste avant la position signalée : une virgule oubliée entre deux éléments, ou un guillemet simple là où il fallait un guillemet double.
S'en prémunir dans le code
Vérifier le statut et le type de contenu avant l'analyse transforme une erreur de syntaxe déroutante en un message qui dit ce qui s'est réellement passé :
async function getJson(url) {
const res = await fetch(url);
const type = res.headers.get('content-type') || '';
if (!res.ok || !type.includes('application/json')) {
const body = await res.text();
throw new Error(`Expected JSON from ${url}, got ${res.status} ${type}: ${body.slice(0, 100)}`);
}
return res.json();
}
Le même principe vaut côté serveur : faites renvoyer aux routes d'API des corps d'erreur en JSON plutôt que des pages d'erreur HTML, accompagnés de l'en-tête Content-Type: application/json. Pour le message voisin qui apparaît quand le corps est vide ou tronqué, consultez Unexpected end of JSON input.