Unexpected Token in JSON: Was der Fehler bedeutet und wie Sie ihn beheben
Dieser Fehler bedeutet, dass der Text, den Sie parsen wollten, kein JSON ist. Das genannte Zeichen verrät meist ziemlich genau, was stattdessen angekommen ist.
Sie rufen JSON.parse() oder response.json() auf und erhalten statt der erwarteten Daten einen SyntaxError. Der genaue Wortlaut hängt vom Browser ab, die Bedeutung ist aber immer dieselbe: Der Parser hat den Text von Anfang an gelesen und ist auf ein Zeichen gestoßen, das an dieser Stelle in gültigem JSON nicht stehen darf. Das zitierte Zeichen und die Position sind die nützlichsten Hinweise, die Sie bei der Fehlersuche haben.
Derselbe Fehler in verschiedenen Engines
Neuere Versionen von Chrome und Node.js haben den Wortlaut der Meldung geändert. In Suchergebnissen, Foren und älteren Logs begegnen Ihnen deshalb beide Varianten.
| Wo die Meldung erscheint | Meldung |
|---|---|
| Chrome, Edge, Node.js 20 und neuer | Unexpected token '<', "<!DOCTYPE "... is not valid JSON |
| Ältere Chrome-Versionen und 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“ oder „line 1 column 1“ heißt: Schon das allererste Zeichen war falsch. Das deutet fast immer darauf hin, dass die Antwort überhaupt kein JSON ist – und nicht auf einen kleinen Tippfehler irgendwo innerhalb eines JSON-Dokuments.
Die übliche Ursache: eine HTML-Seite statt JSON
Ein unerwartetes < an Position 0 ist mit großem Abstand die häufigste Variante. Ihr Code hat bei einer API JSON angefordert, der Server hat aber mit einer HTML-Seite geantwortet, und HTML beginnt mit <!DOCTYPE html> oder <html>. Typische Gründe dafür:
- Eine falsche URL: Ein Tippfehler oder ein fehlendes
/api-Präfix liefert die 404-Seite der Website. - Ein Serverfehler: Das Framework rendert eine HTML-Fehlerseite mit Status 500.
- Eine abgelaufene Sitzung: Die Anfrage wird auf eine Login-Seite umgeleitet, und
fetchfolgt der Weiterleitung, ohne etwas zu melden. - Ein Fallback der Single-Page-App: Der Dev-Server oder das Hosting liefert für jeden unbekannten Pfad
index.htmlaus, und zwar mit Status 200. - Ein Proxy, ein CDN oder eine Firewall dazwischen schickt eine eigene HTML-Fehlerseite oder eine Challenge-Seite.
Am schnellsten bestätigen Sie den Verdacht, indem Sie sich die rohe Antwort ansehen, bevor Sie sie parsen:
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)); // shows the HTML if that is what came back
Im Browser geht es auch ohne Code: Öffnen Sie in den Entwicklertools den Bereich „Netzwerk“, klicken Sie die Anfrage an und sehen Sie sich den Reiter „Antwort“ an. Steht dort HTML, beheben Sie die URL, die Authentifizierung oder den Serverfehler. Der Parsing-Code selbst ist dann in Ordnung und muss nicht angefasst werden.
Andere Zeichen und worauf sie hinweisen
| Aktuelle Meldung (ältere Meldung) | Was Sie geparst haben | Lösung |
|---|---|---|
"undefined" is not valid JSON (Unexpected token u in JSON at position 0) | Den Wert undefined, zum Beispiel einen fehlenden localStorage-Schlüssel oder eine nicht gesetzte Variable | Vor dem Parsen prüfen, ob der Wert existiert |
"[object Object]" is not valid JSON (Unexpected token o in JSON at position 1) | Ein bereits geparstes Objekt, das JSON.parse in einen String umgewandelt hat | Das Objekt direkt verwenden und nicht ein zweites Mal parsen |
Expected property name or '}' in JSON at position 1 | Einfache Anführungszeichen oder Schlüssel ohne Anführungszeichen, wie in {'a': 1} oder {a: 1} | Jeden Schlüssel und jeden String in doppelte Anführungszeichen setzen |
Expected double-quoted property name in JSON at position 8 | Ein nachgestelltes Komma, wie in {"a": 1,} | Das Komma vor der schließenden geschweiften Klammer entfernen |
Unexpected token 'N', "{"a": NaN}" is not valid JSON | NaN, Infinity oder undefined innerhalb der Daten | Durch null oder eine Zahl ersetzen |
| Eine Meldung, die an Position 0 ein unsichtbares oder scheinbar leeres Zeichen zitiert | Eine Byte Order Mark (BOM) am Anfang einer Datei, wie sie manche Windows-Editoren beim Speichern schreiben | Die Datei als UTF-8 ohne BOM speichern oder das erste Zeichen entfernen |
Daten parsen, die schon geparst sind
Bibliotheken liefern oft fertige Objekte. response.json() gibt bereits ein JavaScript-Objekt zurück, und bei axios steckt in response.data ebenfalls schon eines. Übergeben Sie dieses Objekt an JSON.parse, wird es zuerst in den String "[object Object]" umgewandelt, und das scheitert an Position 1. Die Lösung ist, den überflüssigen Parse-Aufruf zu entfernen:
const data = await res.json();
// JSON.parse(data) <- fails: data is already an object
console.log(data.items);
Einen Fehler in echtem JSON finden
Liegt die gemeldete Position irgendwo in der Mitte, ist der Text tatsächlich JSON, nur eben mit einem Fehler darin. Fügen Sie ihn in den JSON Validator ein: Er verwendet denselben Parser wie Ihr Browser, zeigt die Meldung mit Position und Zeile an und formatiert das Dokument, sobald es gültig ist. Der eigentliche Fehler steht meist kurz vor der gemeldeten Position, etwa ein fehlendes Komma zwischen zwei Elementen oder ein einfaches Anführungszeichen, wo ein doppeltes hingehört.
Im eigenen Code vorbeugen
Wer vor dem Parsen Statuscode und Content-Type prüft, macht aus einem verwirrenden Syntaxfehler eine Meldung, die sagt, was wirklich passiert ist:
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();
}
Dasselbe Prinzip gilt auf der Serverseite: Geben Sie in API-Routen Fehler als JSON zurück statt als HTML-Fehlerseiten, und senden Sie dazu den Header Content-Type: application/json. Für die eng verwandte Meldung, die bei einem leeren oder abgeschnittenen Body erscheint, lesen Sie Unexpected end of JSON input.