← All posts
Web developmentPublished · 7 min read

Unexpected end of JSON input — What It Really Means (Empty Body, 204, HEAD, no-cors) and How to Fix It

SyntaxError: Unexpected end of JSON input is short and unhelpful, and most explanations list every possible cause at once. I set up a small local server and reproduced each case in Chrome 154, Node.js 24 and Python 3.11. The result narrows it down: in current Chrome and Node this exact message appears when there was nothing to parse at all. A JSON that was cut off part-way produces a different message with a position, and a no-cors request drops the word JSON. Below is each case with the exact text you will see, why it happens, and a fetch wrapper that stops it.

JSON Formatter & Validator (free, in your browser) — Actual screen
Actual screen
Free tool featured in this guide
JSON Formatter & Validator (free, in your browser)

Paste what the server actually returned to see whether it is valid JSON, and where it breaks — line and column. It runs in your browser; nothing is sent anywhere.

  • ✓ Free
  • ✓ No install, no sign-up
  • ✓ Runs in your browser
  • ✓ Files are never uploaded

🔒 Your file is never sent to a server or anywhere else — it is processed only in your own browser.

Link goes to — a page on this same site (coding-now.com)
🔒 https://www.coding-now.com/en/json-formatter

What the message means — measured

I ran the same inputs through JSON.parse in Chrome 154 and Node.js 24.13, and through Python's json.loads. Chrome and Node gave identical messages. The phrase Unexpected end of JSON input appeared only for input that was empty or only whitespace. Everything else that ended early got a more specific message.

InputChrome 154 / Node 24Python 3.11
"" (empty)Unexpected end of JSON inputExpecting value: line 1 column 1 (char 0)
" " (spaces)Unexpected end of JSON inputExpecting value: line 1 column 4 (char 3)
{"ok":true,"items":[1,2Expected ',' or ']' after array element in JSON at position 23 (line 1 column 24)Expecting ',' delimiter: line 1 column 24 (char 23)
{"ok":true,"name":"helUnterminated string in JSON at position 22 (line 1 column 23)Unterminated string starting at: line 1 column 19 (char 18)
{Expected property name or '}' in JSON at position 1 (line 1 column 2)Expecting property name enclosed in double quotes: line 1 column 2 (char 1)

So if you see the exact words Unexpected end of JSON input in a current browser or Node, look for an empty string, not a broken JSON. Many older articles say a truncated file causes this message; that may have been true of older engine versions, which I did not test. In other browsers the wording differs — MDN's JSON.parse error reference lists forms such as JSON.parse: unexpected end of data.

What res.json() or JSON.parse received decides the message. Measured in Chrome 154 and Node 24 against a local test server.

Where the empty body comes from

Almost always the empty string is the response body. I made a local server with one route per case and called res.json() on each from a Chrome page and from Node's built-in fetch.

  • 204 No Content — common after DELETE or a save. The response had status 204, no Content-Length, and res.text() returned an empty string. res.json() threw Unexpected end of JSON input.
  • A HEAD request — HEAD never has a body, even when GET on the same URL returns JSON. Same error.
  • 200 with an empty body — a server bug or an endpoint that returns nothing on success. Same error.
  • 500 (or 404) with an empty body — fetch does not reject on HTTP errors, so your code goes on to parse the empty error body. Chrome's message for this one carried a prefix: Failed to execute 'json' on 'Response': Unexpected end of JSON input. Node's did not.

Python behaves differently on that last point. urllib.request.urlopen raised HTTP Error 500: Internal Server Error before any JSON was read, so in Python an empty error body shows up as an HTTP error instead.

mode: 'no-cors' — 'Unexpected end of input'

If you added mode: 'no-cors' to get past a CORS error, the request succeeds but you cannot read the answer. Fetching JSON from another origin that way gave a response with type opaque and status 0, its text was empty, and res.json() threw Unexpected end of input — note that the word JSON is missing from this one.

no-cors is not a way around CORS; it is a way to send a request whose response you promise not to read. To read JSON from another origin, the server has to send the CORS headers, or you call it from your own server.

Reading the body twice is a different error

A response body can be read once. Calling res.json() after res.text() (often because a log line read it first) gave Failed to execute 'json' on 'Response': body stream already read in Chrome and Body is unusable: Body has already been read in Node. Read it once into a variable, or call res.clone() before the first read.

The fix: check, then parse

Treat an empty body as an expected answer instead of a crash. This wrapper returned null for the 204, HEAD and empty-200 cases and threw a clear HTTP error for the 500:

javascript
async function getJson(url, options) {
  const res = await fetch(url, options);
  if (!res.ok) throw new Error(`HTTP ${res.status} for ${url}`);
  if (res.status === 204) return null;
  const text = await res.text();
  if (!text.trim()) return null;      // empty body: nothing to parse
  return JSON.parse(text);             // a real JSON error now has a position
}

In Python the same idea is to read the bytes and parse only if something came back:

python
import json, urllib.request

with urllib.request.urlopen(url) as r:
    body = r.read()
data = json.loads(body) if body.strip() else None

When it still fails, log res.status, res.headers.get('content-type') and the first 200 characters of the text. If the text starts with <, the server sent HTML — that is the Unexpected token '<' error, covered in the JSON parse errors guide on this site.

FAQ

Q. Does Unexpected end of JSON input mean my JSON is broken?

Usually not. In Chrome 154 and Node 24 it appeared only for an empty or whitespace-only input. A JSON that was cut off part-way gave a different message with a position, such as Expected ',' or ']' after array element in JSON at position 23.

Q. Why does it happen only sometimes?

Because the server only sometimes sends an empty body — for example 204 after a delete, or an empty response when it hits an error. Log the status code of the failing request; it is usually 204 or a 4xx/5xx.

Q. I get 'Unexpected end of input' without the word JSON. Is that the same?

In my test that came from a fetch with mode: 'no-cors' to another origin. The response is opaque with status 0, so its body is empty to your code. Remove no-cors and fix CORS on the server instead.

Q. It happens when I read a .json file. What should I check?

Check that the file is not zero bytes or only whitespace — JSON.parse of an empty string gives exactly this message. A file that was cut off gives a message with a position instead.

Free tool featured in this guide
JSON Formatter & Validator (free, in your browser)

Paste what the server actually returned to see whether it is valid JSON, and where it breaks — line and column. It runs in your browser; nothing is sent anywhere.

  • ✓ Free
  • ✓ No install, no sign-up
  • ✓ Runs in your browser
  • ✓ Files are never uploaded

🔒 Your file is never sent to a server or anywhere else — it is processed only in your own browser.

Link goes to — a page on this same site (coding-now.com)
🔒 https://www.coding-now.com/en/json-formatter

More posts