# SyntaxError: “Unexpected end of JSON input”

> SyntaxError: Unexpected end of JSON input. The body is empty or cut off: check res.ok, handle 204 responses, and never call JSON.parse on an empty string.

Canonical: https://app369.com/fix/unexpected-end-of-json-input/
Last updated: 2026-11-08

res.json() or JSON.parse() throws SyntaxError: Unexpected end of JSON input (in Firefox, JSON.parse: unexpected end of data). The text being parsed ended before the JSON was complete. Most often it was empty: a 204 No Content reply, an error with no body, an empty string, or a truncated body. Safari words it JSON Parse error: Unexpected EOF.

**Short answer**

Check the response before parsing it. If res.status is 204 or the body is empty, don’t call res.json(). If res.ok is false, read res.text() and log it, because error responses are often empty or not JSON. For JSON.parse, guard against empty strings, and handle null from localStorage. If the body is cut off part-way, the server crashed or timed out mid-response: check its logs.

## **Why the JSON ended early, and the fix**

1. 01 ### **The response has no body**
  > “The response body cannot be parsed as JSON.” [**MDN, Response: json() method, exceptions**](https://developer.mozilla.org/en-US/docs/Web/API/Response/json) A 204 No Content reply, a DELETE handler that ends with res.end(), or an error response with no body gives res.json() an empty string to parse. Check the status and only parse when there is content.```
const res = await fetch(url, { method: 'DELETE' });
if (!res.ok) throw new Error(\`HTTP ${res.status}: ${await res.text()}\`);
const data = res.status === 204 ? null : await res.json();
```
2. 02 ### **An error status is parsed as if it succeeded**
  > “if the server responds with an error like 404, then fetch() fulfills with a Response, so we have to check the status before we can read the response body.” [**MDN, Using the Fetch API**](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) fetch() does not reject on 404 or 500, so code that calls res.json() straight away tries to parse an empty or HTML error body. Check res.ok first.
3. 03 ### **JSON.parse on an empty string** An empty string from localStorage, a form field or an empty environment variable throws this error. A missing key gives null, which parses without error but breaks the code after it. Parse only when there is a value, and fall back to a default.```
function readJson(key, fallback) {
  const raw = localStorage.getItem(key);
  if (!raw) return fallback;
  try { return JSON.parse(raw); } catch { return fallback; }
}
```
4. 04 ### **The server sent half a response** If the body stops part-way, the server crashed, hit a timeout or ran out of memory while writing, or a proxy cut the connection. The client fix is a retry; the real fix is in the server logs at that timestamp.

Checked against the vendor’s docs on November 8, 2026: [MDN: Response json() method](https://developer.mozilla.org/en-US/docs/Web/API/Response/json); [MDN: Using the Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch); [MDN: SyntaxError: JSON.parse: bad parsing](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/JSON_bad_parse).

## **Rather hand it over?**

Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.

- [from $450**App Fix Ticket**One reproducible bug in an existing mobile or web app, diagnosed and fixed.**See scope and start**](https://app369.com/fixed-price/flutter-firebase-bug-fix/)
- [from $450**AI-Built App Rescue**A Lovable, Bolt or Cursor app checked end to end in 3 days, then its worst problems fixed at a fixed price.****No issues worth fixing, no charge.**** If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.**See scope and start**](https://app369.com/fixed-price/ai-app-rescue/)

Related: [**“Unexpected token < in JSON”**](https://app369.com/fix/unexpected-token-in-json/) · [**“TypeError: Failed to fetch”**](https://app369.com/fix/typeerror-failed-to-fetch/) · [**“Cannot read properties of undefined”**](https://app369.com/fix/cannot-read-properties-of-undefined/)

Questions

## **More on this error**

<details>

<summary>**How is this different from “Unexpected token < in JSON”? **+</summary>

Unexpected token < means the body was HTML, usually an error or index page. Unexpected end means the body was empty or cut off. Both are fixed by checking res.ok and the status before parsing.

</details>

<details>

<summary>**Can I read the body twice to log it? **+</summary>

No. A body can be read once, so a second res.json() or res.text() throws a TypeError. Read it once with res.text(), log it, then JSON.parse the text.

</details>

<details>

<summary>**Can you fix it for me? **+</summary>

If one bug is the whole problem, the App Fix Ticket covers it: a written diagnosis first, then the fix. If the app has more going on, the Launch Check is a written check of the whole app. Each issue found is rated critical, high, medium or low, with where it is and how it was confirmed. No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.

</details>

A different error?

## **Describe it and get a written quote**

Send the error and what you were doing. You get a written scope, a fixed price and a timeline; Simon replies by email, usually within one business day.

[**Describe your problem **→](https://app369.com/contact/) [**All fixes**](https://app369.com/fix/)