Unexpected end of JSON input / Unexpected end of input
JSON.parse threw Unexpected end of JSON input. The parser reached the end of the string before the value finished — often because the string was empty, cut off, or not JSON at all.
What the error means
SyntaxError: Unexpected end of JSON input (Firefox sometimes says JSON.parse: unexpected end of data; Node may say Unexpected end of JSON input) means the parser hit EOF while still expecting more tokens — a missing }/], or an empty string.
JSON.parse("") // Unexpected end of JSON input
JSON.parse("{") // same family — truncated
JSON.parse("
Browsers' response.json() is just JSON.parse on the body. An HTTP 204, empty 200, or a proxy that dropped the body all land here.
Cause table
| What you see | Likely cause | What to do |
|---|---|---|
| Empty string / length 0 | 204 No Content, DELETE with no body, wrong URL returning blank, CORS opaque mishandled | Do not call .json() on empty; branch on status and Content-Length / text length |
Starts with < | HTML error page (404/500 login page) fed to JSON.parse | Check status; see Unexpected token in JSON |
| Looks like half an object | Truncated response (proxy buffer, killed worker, phone flaky network) | Retry; check server logs / 502 / OOM 137 |
| Works in curl, fails in browser | Different URL, extension blocking, service worker cache, ERR_BLOCKED_BY_CLIENT | Compare raw bodies; disable extensions; Network tab → Response |
| Node fs / hand-rolled buffer | Read file before write finished; partial chunk without assembling | Await the full Buffer/string; validate with a formatter |
| Double decode | Body already an object (axios) then passed to JSON.parse again; or Base64 layer forgotten | Parse once; decode Base64 first via Base64 tool |
Safe fetch pattern
const res = await fetch(url, { headers: { Accept: "application/json" } });
const text = await res.text(); // always read raw first while debugging
if (!res.ok) {
throw new Error(`HTTP ${res.status}: ${text.slice(0, 200)}`);
}
if (!text) {
return null; // empty body is not JSON
}
try {
return JSON.parse(text);
} catch (err) {
console.error("Bad JSON body:", text.slice(0, 500));
throw err;
}
Paste the logged body into the JSON formatter — it shows the exact parse error location. Mystery Content-Type blob? What is this?
Server-side tips
- Always send a body for endpoints clients call
.json()on — or document 204 and teach clients to skip parse. - Set
Content-Type: application/jsonand avoid returning HTML error pages on API routes (use JSON error shapes). - If a reverse proxy buffers, watch for upstream crashes mid-response (502, worker heap OOM).
- Gzip/brotli mismatches can truncate in broken clients — compare
curl -vwith browser Network.
Close cousins
- Unexpected token < in JSON — body is HTML; see Unexpected token in JSON.
- Unexpected end of input (no "JSON") — often a truncated
.jsmodule or eval string, notJSON.parse. - Failed to fetch — network/CORS layer before a body exists; see TypeError: Failed to fetch.
Related
Unexpected token in JSON · JSON formatter · TypeError: Failed to fetch · 502 Bad Gateway · Base64 is not encryption
Questions
What causes Unexpected end of JSON input?
JSON.parse hit the end of the string too early — empty body, truncated payload, or incomplete object/array.
Why does response.json() fail on a 204?
204 No Content has an empty body. Check status and skip .json() when there is nothing to parse.
How is this different from Unexpected token < in JSON?
Token < usually means an HTML page (error/login) was parsed as JSON. End of input means emptiness or truncation.
How do I debug it quickly?
await response.text(), log the first hundreds of characters, paste into the JSON formatter, and confirm the HTTP status.
Can a proxy cause this?
Yes — upstream crash, buffer limit, or compression bugs can deliver a partial body that fails to parse.
Does an empty array or object trigger it?
No. [] and {} are valid. Only empty string or cut-off text does.
Published .