SyntaxError: Unexpected end of JSON input means the JSON parser reached the end of the string before finding a complete, valid JSON document. The JSON is cut off somewhere — a bracket never closed, the response was truncated, or you only pasted part of the data.
Try it directly in your browser:
Validate your JSON →The four main causes
1. Truncated API response
Network timeouts, response size limits, or streaming errors can cut off an API response mid-transfer. The beginning of the JSON is valid, but the document ends abruptly without all closing braces and brackets.
// Truncated — missing the closing ] and }
{"users": [
{"id": 1, "name": "Alice"},
{"id": 2, "name": "Bob"
To diagnose: log the raw response text before parsing. Check the final characters — if they don't end with a complete JSON value (}, ], a quoted string, a number, true, false, or null), the response was cut.
2. Unclosed brackets or braces in hand-written JSON
When editing JSON manually, it's easy to open a brace or bracket and forget to close it, especially in deeply nested structures.
// Missing closing } for the "address" object and } for the outer object
{
"name": "Alice",
"address": {
"city": "London",
"postcode": "SW1A 1AA"
The parser reads the entire string, reaches the end, and realises it's still waiting for the closing tokens it expected.
3. Parsing an empty string
A 204 No Content API response, or an endpoint that returns nothing on success, gives you an empty body. Calling JSON.parse('') throws "Unexpected end of JSON input" because an empty string is not valid JSON.
// This throws:
JSON.parse(''); // SyntaxError: Unexpected end of JSON input
// Guard against empty responses:
const text = await res.text();
const data = text ? JSON.parse(text) : null;
4. Partial file write
If a process writing a JSON file crashes or is interrupted mid-write, the file will be incomplete. Reading and parsing an incomplete JSON file produces this error. Always write JSON files atomically: write to a temporary file, then rename it to the target filename, so readers never see a partial write.
How to find the unclosed bracket
For large JSON blobs, finding the missing bracket manually is tedious. The fastest approach is to paste the JSON into the JSON Formatter. The tree view renders each nested object and array as a collapsible node. A structure that's open but never closed will be visible in the tree as an empty or incomplete branch.
You can also count brackets programmatically to identify the imbalance:
function countBrackets(json) {
let braces = 0, brackets = 0;
let inString = false;
for (let i = 0; i < json.length; i++) {
const char = json[i];
// Track strings to skip brackets inside them
if (char === '"' && json[i - 1] !== '\\') inString = !inString;
if (inString) continue;
if (char === '{') braces++;
if (char === '}') braces--;
if (char === '[') brackets++;
if (char === ']') brackets--;
}
return { unclosedBraces: braces, unclosedBrackets: brackets };
}
// Example:
countBrackets('{"name": "Alice", "scores": [1, 2');
// { unclosedBraces: 1, unclosedBrackets: 1 }
Two more causes that only happen in fetch()
The four causes above are about the JSON itself being incomplete. When the error comes out of a fetch() call there are two further possibilities, and in both the JSON was never the problem — res.json() was handed an empty body.
You already read the response body
A Response body is a readable stream, and a stream can only be consumed once. The usual way to trip over this is adding a debug log: res.text() drains the stream, and the res.json() that follows reads nothing and throws.
// ❌ the log consumes the stream; res.json() then gets an empty body
// fetch('/api/data').then(res => {
// res.text().then(t => console.log('raw:', t));
// return res.json(); // SyntaxError: Unexpected end of JSON input
// });
// ✅ read once, then work from the text
const res = await fetch('/api/data');
const text = await res.text();
console.log('raw:', text);
const data = text ? JSON.parse(text) : null;
// ✅ or clone before reading, if you genuinely need both
const res2 = await fetch('/api/data');
const data2 = await res2.clone().json();
console.log('raw:', await res2.text());
This has its own reference if you want the longer version: Failed to execute 'json' on 'Response': body stream already read.
A cross-origin request failed before it returned anything
When a cross-origin fetch() fails CORS, the browser hands your code an error or an opaque response rather than the server's actual reply, so there is no body to parse. The giveaway is that the real explanation is in the browser console as a CORS policy message, not in the exception you caught.
Check the console before you touch the parsing code — a message naming Access-Control-Allow-Origin means the fix belongs on the server, and No 'Access-Control-Allow-Origin' header is present covers it. If the console instead complains about the preflight, see Response to preflight request doesn't pass access control check.
The same error in Python
“Unexpected end of JSON input” is the JavaScript/Node wording. Python's json module raises the same underlying problem — a JSON document that ends too soon — but with a different message depending on where it was cut off:
import json
# empty or whitespace-only body:
json.loads("")
# json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
# truncated mid-structure:
json.loads('{"users": [{"id": 1}')
# json.decoder.JSONDecodeError: Expecting ',' delimiter: line 1 column 20 (char 19)
# cut off inside a string:
json.loads('{"name": "Ali')
# json.decoder.JSONDecodeError: Unterminated string starting at: line 1 column 10 (char 9)
So the fix is identical — find where the JSON was truncated — but the message you search for differs. If you're on Python, the two you'll hit most are Expecting value: line 1 column 1 (char 0) (usually an empty response) and Unterminated string starting at (a response cut off mid-value). Guard the same way: check the body is non-empty before calling json.loads().
Validating before parsing
Use the JSON Validator to check any JSON before you parse it in production. The validator reports the exact line and character position of the error, which is far more useful than the generic "unexpected end of input" message from most runtimes.
Defensive parsing in production code
async function safeParseResponse(res) {
const text = await res.text();
if (!text || !text.trim()) {
return null; // Empty response — not an error, just nothing to parse
}
try {
return JSON.parse(text);
} catch (err) {
console.error('Failed to parse JSON response:', err.message);
console.error('Response body (first 500 chars):', text.slice(0, 500));
throw err;
}
}
Frequently Asked Questions
What does 'Unexpected end of JSON input' mean?
It means the JSON parser reached the end of the text before the document was complete — the JSON is cut off. Every open brace and bracket must be closed, and the last value must finish, before the string ends. When the parser runs out of characters while still expecting more, it throws this error. It is almost always truncated or incomplete data, not a syntax typo in the middle of the document.
What causes 'Unexpected end of JSON input'?
The JSON parser ran out of characters before finding a complete, valid JSON document. Common causes are: a truncated API response (network timeout or size limit), an unclosed bracket or brace in hand-written JSON, a partial file write that was interrupted, or copy-pasting only part of a JSON blob.
How do I find the unclosed bracket in JSON?
Paste the JSON into a JSON formatter with a tree view. The tree view renders each nested object and array as an expandable node, making it immediately obvious where a structure is left open. Alternatively, count the opening and closing braces — in valid JSON they must be equal for { } pairs and [ ] pairs.
Can an empty string cause 'Unexpected end of JSON input'?
Yes. Calling JSON.parse('') throws "Unexpected end of JSON input" because an empty string is not valid JSON. This happens when an API returns an empty body (for example, a 204 No Content response) and your code tries to parse it. Always check that the response body is non-empty before parsing.
Ready to validate your json?
Open JSON Validator →