Unexpected End of JSON Input: Was der Fehler bedeutet und wie Sie ihn beheben
Dem Parser ist der Text ausgegangen, bevor er einen vollständigen Wert gefunden hat – und in den meisten Fällen liegt das daran, dass überhaupt kein Text da war.
Sie rufen JSON.parse() oder response.json() auf und erhalten SyntaxError: Unexpected end of JSON input. Anders als bei einem „Unexpected token“ zeigt dieser Fehler nicht auf ein falsches Zeichen. Er bedeutet, dass der Parser beim letzten Zeichen angekommen ist, während er noch auf einen Wert gewartet hat. Entweder war der Text leer, oder er endet mitten in einem Dokument. Diese beiden Fälle auseinanderzuhalten ist schon die ganze Arbeit, und dafür genügt eine einzige Log-Zeile.
Derselbe Fehler in verschiedenen Umgebungen
| Wo die Meldung erscheint | Meldung |
|---|---|
Chrome, Edge und Node.js, JSON.parse | Unexpected end of JSON input |
Chrome und Edge, response.json() | Dieselbe Meldung, manchmal mit dem Präfix Failed to execute 'json' on 'Response': |
Chrome, eine Antwort ganz ohne Body, etwa eine opake no-cors-Antwort | Unexpected end of input |
| Firefox | JSON.parse: unexpected end of data at line 1 column 1 of the JSON data |
| Safari | JSON Parse error: Unexpected EOF |
Python, json.loads | Expecting value: line 1 column 1 (char 0) |
Nennt die Meldung Zeile 1, Spalte 1 oder Zeichen 0, hat der Parser nichts zum Lesen gefunden. Ein leerer Text ist kein gültiges JSON: Die kürzesten gültigen Dokumente sind Werte wie 0, null, "" oder {}.
Die übliche Ursache: ein leerer Body oder ein leerer String
Bevor Sie in den Daten nach einem Fehler suchen, prüfen Sie, ob überhaupt Daten angekommen sind. Das sind die typischen Quellen für einen leeren String:
- 204 No Content. Viele APIs beantworten ein erfolgreiches
DELETEoderPUTmit Status 204 und ohne Body.res.okist bei 204true, diese Prüfung schützt den nachfolgenden Aufruf vonres.json()also nicht. - HEAD-Anfragen. Eine Antwort auf
HEADhat nie einen Body, ganz gleich, was in ihren Headern steht. - fetch mit
mode: 'no-cors'. Damit umgehen Sie CORS nicht. Sie erhalten eine opake Antwort mit Status 0 und einem Body, den Ihr Code nicht lesen darf, das Parsen scheitert also immer. Aktivieren Sie CORS auf dem Server oder rufen Sie die API über Ihr eigenes Backend auf. - Ein 200 oder 500 ohne Inhalt. Ein Handler, der seine Ausgabe nie schreibt, oder ein Serverfehler, der die Anfrage beendet, bevor etwas gesendet wurde, erzeugt einen leeren Body mit ganz normalem Statuscode.
- Leere Werte im Speicher und leere Dateien.
localStorage.setItem('cart', ''), eine leeresettings.jsonoder eine Umgebungsvariable, die gesetzt, aber leer ist, übergebenJSON.parseallesamt einen leeren String. - Ein abschließender Zeilenumbruch in zeilenweisem JSON.
text.split('\n').map(JSON.parse)scheitert am leeren String nach dem letzten Zeilenumbruch. Filtern Sie leere Zeilen vorher heraus.
Zwei ähnlich aussehende Fälle verhalten sich anders. Ein fehlender localStorage-Schlüssel liefert null, und JSON.parse(null) gibt null zurück, ohne eine Ausnahme zu werfen. Eine nicht gesetzte Variable ist undefined und scheitert stattdessen mit "undefined" is not valid JSON; diesen Fall behandelt der Guide Unexpected token in JSON.
Um herauszufinden, welcher Fall bei Ihnen vorliegt, lesen Sie den Body als Text, bevor Sie ihn parsen:
const res = await fetch('/api/cart', { method: 'DELETE' });
const text = await res.text();
console.log(res.status, res.type, res.headers.get('content-type'), text.length);
// Typical results:
// 204 basic null 0 -> nothing to parse
// 0 opaque null 0 -> a no-cors request
// 200 basic application/json 8192 -> there is text: check whether it is complete
Im Browser zeigt der Bereich „Netzwerk“ der Entwicklertools dasselbe: Ist der Reiter „Antwort“ leer, liegt das Problem in der Anfrage oder beim Server, nicht in Ihrem Parsing-Code.
Wenn der Text abgeschnitten wurde
Ist der Text nicht leer, endet er, bevor das Dokument vollständig ist. Aktuelle Versionen von Chrome und Node.js melden „Unexpected end of JSON input“ nur dann, wenn der Text genau dort aufhört, wo ein Wert beginnen sollte, oder mitten in true, false oder null. An jeder anderen Stelle erzeugt dieselbe Kürzung eine andere Meldung:
| Text endet mit | Meldung in aktuellem Chrome und Node.js |
|---|---|
{"id": | Unexpected end of JSON input |
{"tags":["a", | Unexpected end of JSON input |
{"ok":tru | Unexpected end of JSON input |
{"name":"Al (11 Zeichen) | Unterminated string in JSON at position 11 |
{"id":42 (8 Zeichen) | Expected ',' or '}' after property value in JSON at position 8 |
Die praktische Faustregel: Entspricht die Position in der Meldung der Länge des Textes, wurde das Dokument abgeschnitten und ist nicht fehlerhaft aufgebaut. Ältere Versionen von Chrome und Node.js haben die meisten dieser Fälle ebenfalls als „Unexpected end of JSON input“ gemeldet. Ältere Logs und Antworten in Foren verwenden diesen Wortlaut deshalb ganz allgemein für abgeschnittene Dokumente.
Abgeschnittenes JSON stammt meist aus einer dieser Quellen:
- Einen Stream stückweise parsen. Daten aus
res.body.getReader(), einem Node.js-data-Event oder einem Socket kommen in Stücken beliebiger Größe an. Ein einzelnes Stück ist selten ein vollständiges Dokument. Sammeln Sie die Stücke und parsen Sie einmal am Ende, oder puffern Sie zeilenweises JSON jeweils bis zum nächsten Zeilenumbruch. - Zu kleiner Speicherplatz. Eine Datenbankspalte, die kürzer ist als das Dokument, speichert in einer Datenbank, die auf Abschneiden statt auf Ablehnen des Schreibvorgangs eingestellt ist, nur den ersten Teil und verwirft den Rest.
- Kopieren aus einer Quelle, die lange Texte kürzt, etwa einem Log-System mit maximaler Zeilenlänge.
- Eine vorzeitig geschlossene Verbindung bei einer Antwort ohne
Content-Length, die auch nicht chunked übertragen wurde. Ist die Länge angegeben, wird eine abgebrochene Verbindung stattdessen als Netzwerkfehler gemeldet: In Node.js schlägtres.json()dann mitTypeError: terminatedfehl.
Im eigenen Code vorbeugen
Lesen Sie den Body als Text, legen Sie fest, was ein leerer Body für diesen Endpunkt bedeutet, und parsen Sie erst danach. So behandeln Sie 204-, HEAD- und leere 200-Antworten an einer Stelle, und die Fehlermeldung bleibt aussagekräftig, wenn etwas anderes schiefgeht:
async function readJson(res) {
const text = await res.text();
if (!res.ok) {
throw new Error(`HTTP ${res.status}: ${text.slice(0, 100) || '(empty body)'}`);
}
if (text.trim() === '') return null; // 204, HEAD or an empty 200
try {
return JSON.parse(text);
} catch (err) {
throw new Error(`Invalid JSON (${text.length} chars): ${err.message}`);
}
}
Bei gespeicherten Werten behandeln Sie leer und fehlend gleich und greifen auf einen Standardwert zurück:
function loadCart() {
const raw = localStorage.getItem('cart');
if (!raw) return []; // null (missing) or '' (empty)
try {
return JSON.parse(raw);
} catch {
return []; // damaged value: start again
}
}
Auf der Serverseite gilt: Seien Sie konsequent. Antworten Sie entweder mit 204, ohne Body und ohne JSON-Content-Type, oder mit einem kleinen JSON-Dokument wie {} oder {"deleted": true}. Eine 200-Antwort mit dem Typ application/json und leerem Body ist genau die Kombination, an der Clients scheitern.
Den Text von Hand prüfen
Ist der Body nicht leer, kopieren Sie ihn aus dem Netzwerk-Bereich oder aus Ihren Logs und fügen Sie ihn in den JSON Validator ein. Er verwendet den Parser des Browsers, zeigt also dieselbe Meldung und Position, die auch Ihr Code bekommen hat, und formatiert das Dokument, sobald es gültig ist. Liegt die gemeldete Position ganz am Ende des eingefügten Textes, suchen Sie den fehlenden Teil bei der Übertragung oder im Speicher, nicht in den Daten. Für Fehler, die ein bestimmtes Zeichen nennen, etwa ein < aus einer HTML-Seite, lesen Sie Unexpected token in JSON.