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 seeLikely causeWhat to do
Empty string / length 0204 No Content, DELETE with no body, wrong URL returning blank, CORS opaque mishandledDo 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.parseCheck status; see Unexpected token in JSON
Looks like half an objectTruncated response (proxy buffer, killed worker, phone flaky network)Retry; check server logs / 502 / OOM 137
Works in curl, fails in browserDifferent URL, extension blocking, service worker cache, ERR_BLOCKED_BY_CLIENTCompare raw bodies; disable extensions; Network tab → Response
Node fs / hand-rolled bufferRead file before write finished; partial chunk without assemblingAwait the full Buffer/string; validate with a formatter
Double decodeBody already an object (axios) then passed to JSON.parse again; or Base64 layer forgottenParse 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/json and 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 -v with 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 .js module or eval string, not JSON.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 .

Try it

Related guides

Newest guides