Correction de l'erreur 'Unexpected token < in JSON at position 0'
Vous appelez response.json() et votre application plante avec SyntaxError: Unexpected token '<' in JSON at position 0. Le caractère < vous indique exactement ce qui s’est passé : votre code attendait du JSON mais a reçu du HTML à la place.
Cette erreur d’analyse JSON apparaît constamment dans les stacks frontend modernes—fetch dans le navigateur, Node.js, routes API Next.js et fonctions serverless. Comprendre pourquoi elle se produit et comment la déboguer rapidement vous fera gagner des heures de frustration.
Points clés à retenir
- L’erreur “Unexpected token <” signifie que vous essayez d’analyser du HTML comme du JSON—le
<provient généralement de<!DOCTYPE html>ou d’une balise HTML. - Les causes courantes incluent des URLs incorrectes, des redirections d’authentification, des erreurs serveur renvoyant des pages HTML et des en-têtes Content-Type manquants.
- Déboguez en vérifiant d’abord le code de statut HTTP, puis l’en-tête Content-Type, puis le corps de réponse brut en utilisant
response.text(). - Créez des wrappers fetch défensifs qui valident les réponses avant de les analyser pour détecter ces problèmes avec des messages d’erreur clairs.
Pourquoi votre API renvoie du HTML au lieu de JSON
L’erreur signifie que JSON.parse() a rencontré un document HTML alors qu’il attendait du JSON valide. Le < en position 0 est généralement le caractère d’ouverture de <!DOCTYPE html> ou d’une balise HTML.
Plusieurs scénarios provoquent cette incompatibilité de Content-Type :
URLs d’endpoint incorrectes ou mal orthographiées. Une faute de frappe dans votre URL fetch renvoie une page 404—qui est du HTML, pas du JSON.
Redirections d’authentification. Des tokens expirés ou des en-têtes d’authentification manquants déclenchent des redirections vers des pages de connexion. Votre fetch reçoit le HTML de la page de connexion.
Erreurs serveur renvoyant des pages d’erreur HTML. Une erreur 500 de votre passerelle API ou fournisseur cloud renvoie souvent une page d’erreur HTML stylisée plutôt qu’une réponse d’erreur JSON.
Serveurs de développement servant du HTML de repli pour les routes inconnues. De nombreuses SPA renvoient le shell HTML pour les chemins non correspondants, bien que certains serveurs de développement modernes renvoient des payloads d’erreur structurés.
En-têtes Content-Type manquants ou incorrects. Le code serveur qui oublie de définir Content-Type: application/json peut utiliser HTML par défaut.
Un flux de débogage pratique pour les erreurs Fetch API
Lorsque l’analyse JSON échoue, suivez cette séquence pour identifier la cause racine :
Étape 1 : Vérifier le code de statut HTTP
Avant d’analyser, vérifiez le statut de la réponse. Un statut 4xx ou 5xx indique souvent que la réponse ne sera pas du JSON :
const response = await fetch('/api/data')
if (!response.ok) {
console.error(`HTTP ${response.status}: ${response.statusText}`)
const text = await response.text()
console.error('Response body:', text.substring(0, 200))
throw new Error(`Request failed with status ${response.status}`)
}
Étape 2 : Valider l’en-tête Content-Type
Vérifiez ce que le serveur prétend envoyer :
const contentType = response.headers.get('content-type')
if (!contentType || !contentType.includes('application/json')) {
const text = await response.text()
throw new Error(`Expected JSON, received: ${contentType}. Body: ${text.substring(0, 100)}`)
}
const data = await response.json()
Étape 3 : Logger le corps de réponse brut
Lorsque l’analyse échoue, utilisez response.text() au lieu de response.json() pour voir ce que vous avez réellement reçu :
async function fetchWithDebug(url) {
const response = await fetch(url)
const text = await response.text()
try {
return JSON.parse(text)
} catch (error) {
console.error('Failed to parse JSON. Raw response:', text.substring(0, 500))
throw error
}
}
Discover how at OpenReplay.com.
Pièges courants en conditions réelles
URLs de base API incorrectes en production. Des variables d’environnement pointant vers de mauvais domaines ou des slashes de fin manquants provoquent des 404 qui renvoient du HTML.
Passerelles API et CDN interceptant les requêtes. Des services comme Cloudflare, AWS API Gateway ou Vercel peuvent renvoyer leurs propres pages d’erreur HTML pour les limites de débit, les timeouts ou les mauvaises configurations.
Redirections de middleware et App Router Next.js. Les redirections de middleware ou d’authentification renvoient souvent du HTML, bien que certains chemins de redirection émettent de petits payloads JSON à la place.
Code serveur sans en-têtes JSON. Votre gestionnaire API renvoie des données mais oublie de définir le type de contenu de la réponse :
// ❌ Content-Type manquant
res.send({ data: 'value' })
// ✅ Réponse JSON explicite
res.json({ data: 'value' })
Problèmes CORS. Les navigateurs bloquent les requêtes preflight échouées avant l’exécution de votre code, mais des serveurs ou proxies mal configurés peuvent toujours renvoyer une page d’erreur HTML que votre appel fetch reçoit.
Pattern fetch défensif
Encapsulez vos appels fetch avec une validation pour détecter ces problèmes tôt :
async function safeFetch(url, options = {}) {
const response = await fetch(url, options)
if (!response.ok) {
const body = await response.text()
throw new Error(`HTTP ${response.status}: ${body.substring(0, 100)}`)
}
const contentType = response.headers.get('content-type')
if (!contentType?.includes('application/json')) {
const body = await response.text()
throw new Error(`Invalid content-type: ${contentType}`)
}
return response.json()
}
Conclusion
L’erreur “Unexpected token <” signifie toujours que vous analysez du HTML comme du JSON. Déboguez en vérifiant d’abord le code de statut, puis l’en-tête Content-Type, puis le corps de réponse brut. La plupart des cas remontent à des URLs incorrectes, des redirections d’authentification ou des erreurs serveur renvoyant des pages HTML. Créez des wrappers fetch défensifs qui valident les réponses avant de les analyser pour détecter ces problèmes avec des messages d’erreur clairs.
FAQ
Les environnements de production ont souvent des configurations différentes. Vérifiez que votre variable d'environnement d'URL de base API est correctement définie, vérifiez que vos tokens d'authentification sont valides et confirmez que tous les proxies ou CDN entre votre frontend et votre API sont correctement configurés. Les serveurs de production peuvent également avoir des politiques CORS plus strictes qui provoquent l'échec des requêtes.
Oui. Encapsulez vos appels fetch dans une fonction défensive qui vérifie le statut de la réponse et l'en-tête Content-Type avant d'appeler response.json(). Cela vous permet de gérer l'erreur de manière élégante et d'afficher un message significatif aux utilisateurs au lieu de planter. Validez toujours les réponses avant de les analyser.
Utilisez l'onglet Réseau de votre navigateur pour inspecter la réponse réelle. Si la réponse affiche du contenu HTML avec un statut 404 ou 500, le serveur renvoie une page d'erreur. Si le statut est 200 mais que le contenu est du HTML, vérifiez votre code serveur pour vous assurer qu'il définit le bon en-tête Content-Type et renvoie du JSON.
La méthode response.json() tente d'analyser le corps de la réponse comme du JSON. Si le corps contient du HTML ou tout contenu non-JSON, l'analyse échoue. La méthode response.text() renvoie simplement la réponse brute sous forme de chaîne sans analyse, c'est pourquoi elle fonctionne quel que soit le type de contenu. Utilisez text() pour le débogage afin de voir ce que vous avez réellement reçu.
Understand every bug
Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.