Unexpected End of JSON Input: Causes and Fixes
· 5 min read
"Unexpected end of JSON input" means the parser ran out of text before the JSON value was complete. Most of the time the string is completely empty (an empty HTTP body, a 204 response, an empty file or an empty localStorage value); otherwise it was cut off, or a closing } or ] is missing. Log text.length and the last 50 characters, and if there is content, paste it into the JSON validator to see where the structure stops.
The quickest diagnosis is the length. Zero means nothing was sent or nothing was read; a non-zero length means the text is incomplete. The two have completely different fixes.
Minimal reproduction
JSON.parse("");
// Chrome / Node: SyntaxError: Unexpected end of JSON input
// Firefox: SyntaxError: JSON.parse: unexpected end of data at line 1 column 1 of the JSON data
// Safari: SyntaxError: JSON Parse error: Unexpected EOF
JSON.parse(" "); // same error: whitespace only
JSON.parse(null); // no error! returns null, because String(null) is "null"Message variants
| Where | Message |
|---|---|
Chrome, Edge, Node (JSON.parse) | SyntaxError: Unexpected end of JSON input |
Chrome (response.json()) | Failed to execute 'json' on 'Response': Unexpected end of JSON input |
| Firefox, empty input | JSON.parse: unexpected end of data at line 1 column 1 of the JSON data |
| Firefox, cut inside an object | JSON.parse: end of data while reading object contents or end of data after property value in object |
| Firefox, cut inside an array | JSON.parse: end of data when ',' or ']' was expected |
| Safari, Bun | SyntaxError: JSON Parse error: Unexpected EOF |
Python json | JSONDecodeError: Expecting value: line 1 column 1 (char 0) for empty input |
In current Chrome and Node, text cut off in the middle of an object, array or string may be reported with a more specific message, such as Expected ',' or '}' after property value in JSON at position 6 or Unterminated string in JSON at position 12, depending on exactly where it stops. Empty input always produces Unexpected end of JSON input. For the other position-based messages, see Unexpected token in JSON.
Causes, most common first
1. The HTTP response has no body
DELETE and PUT endpoints often answer 204 No Content, some POST endpoints answer 201 with an empty body, and HEAD requests never have one. Calling res.json() on any of them throws. An error response with an empty body (a bare 401 or 500 from a proxy) does the same. Read the text first and only parse when there is something to parse:
const res = await fetch(url, { method: "DELETE" });
if (!res.ok) throw new Error("HTTP " + res.status);
const text = await res.text();
const data = text.trim() ? JSON.parse(text) : null; // 204 and empty 200 become nullIf the body is not empty but starts with <, you have the HTML-instead-of-JSON problem instead; see Unexpected token '<', "<!DOCTYPE".
2. An empty string from storage, a file or a form
localStorage.getItem returns null for a missing key, and JSON.parse(null) quietly returns null. But a key that was set to "", an empty file, an empty environment variable or an empty <textarea> all give an empty string, and that throws. Guard explicitly and decide what an empty value should mean:
function readSettings() {
const raw = localStorage.getItem("settings");
if (!raw) return { theme: "light" }; // missing or empty: use defaults
try {
return JSON.parse(raw);
} catch {
localStorage.removeItem("settings"); // corrupted: reset rather than crash on every load
return { theme: "light" };
}
}3. Parsing a Node.js stream chunk instead of the whole body
With the low-level http/https modules, the data event fires once per chunk. Parsing inside it works for small responses and fails as soon as a response is split across chunks, which makes the bug look intermittent. Collect every chunk and parse on end, or use fetch, which buffers for you:
import https from "node:https";
https.get(url, (res) => {
const chunks = [];
res.on("data", (chunk) => chunks.push(chunk));
res.on("end", () => {
const data = JSON.parse(Buffer.concat(chunks).toString("utf8"));
console.log(data);
});
});The same mistake happens when reading a file while another process is still writing it. Write to a temporary file and rename it when complete, so readers never see half a document.
4. Truncated text: size limits, timeouts and LLM output
Log lines capped at a fixed length, a database column that is too short, a proxy that drops a slow connection, a copy-paste that missed the last line, and a language model that hit its token limit all produce JSON that simply stops. Look at the end of the text: if it ends mid-string or mid-number, data is missing and no parser can recover it. For model output, raise the output token limit or ask for smaller pieces; the LLM JSON fixer can close the open brackets so you can see what you did receive, but treat that as a salvage, not a fix.
5. A missing closing bracket in hand-written JSON
In a config file you edited by hand, the usual cause is a } or ] deleted along with the last entry. The JSON fixer closes unbalanced brackets and shows the change, and the validator shows which bracket was left open.
A checklist
- Log
text.length. If it is 0, fix the source of the empty value (status 204, empty file, unset variable), not the parser. - If it is non-zero, log the last 50 characters. A cut-off value means truncation; a complete value with a missing bracket means a hand edit.
- Check the HTTP status and headers.
Content-Length: 0or status 204 explains everything. - In Node, make sure you parse after the stream ends, not inside the
datahandler. - Paste the text into the validator to find the exact spot where the structure is left open.
The common JSON errors hub lists every other error family with a link to its guide.
FAQ
What does "Unexpected end of JSON input" mean?
The JSON text ended before a complete value was read. Usually the string is empty; otherwise it was truncated or is missing a closing bracket or quote.
Why does fetch response.json() throw "Unexpected end of JSON input"?
The response body is empty, typically because the endpoint returns 204 No Content, an empty 201, or an empty error response. Read res.text() first and only call JSON.parse when the text is not empty.
Does JSON.parse(null) throw this error?
No. JSON.parse(null) converts null to the string "null" and returns null. JSON.parse("") and JSON.parse(undefined) do throw, with different messages.
Can a tool repair truncated JSON?
A fixer can close open strings and brackets so the text parses, but it cannot restore missing data. Use the repaired output to inspect what arrived, then fix the truncation at the source.

