SyntaxError: Unexpected end of JSON input means JSON.parse() received a string that stopped before valid JSON syntax was complete — most often an empty string, or a string truncated partway through what should have been a complete JSON document, rather than malformed JSON with actual syntax errors in the middle.
This error specifically indicates the parser ran out of input while still expecting more — a closing brace, bracket, or quote that never arrived — which is a distinct failure mode from other JSON syntax errors that point to a specific invalid character; "unexpected end" means the string just stopped too soon.
Why This Error Happens
JSON.parse() expects a complete, well-formed JSON string. The most common real-world causes are: parsing an HTTP response body that's actually empty (a 204 No Content response, or an error response with no body), a network request that got cut off before completing, or accidentally calling JSON.parse() on a value that was already parsed (or never was valid JSON to begin with, like an empty string from localStorage).
Reproducing the Error
A common fetch-related case:
const response = await fetch("/api/status");
const data = await response.json();
// throws: SyntaxError: Unexpected end of JSON input
// if the endpoint returned a 204 No Content with an empty body
Or reading from localStorage when the key doesn't exist:
const saved = localStorage.getItem("userPrefs"); // returns null if not set
const prefs = JSON.parse(saved);
// throws: Unexpected end of JSON input, because JSON.parse(null) coerces
// null to the string "null" only if explicitly stringified — but an
// empty string or genuinely missing value produces this error directly
Core Concepts Behind This Error
An empty string is not valid JSON, even though it might feel like a reasonable "no data" representation — valid JSON requires at least a minimal value (null, {}, [], a number, string, or boolean), so any code path that can produce an empty string needs to be handled before reaching JSON.parse(), not left to throw.
HTTP status codes that legitimately have no body (204, some error responses) will produce this error if you unconditionally call .json() on the response — checking the response status or content-length before parsing avoids attempting to parse a body that was never meant to contain JSON.
Truncated responses (a network interruption, a proxy timeout cutting off a large response mid-stream) produce this exact error too, distinct from a genuinely empty response — this is a real, if less common, cause worth considering for large response bodies over unreliable connections.
response.json() internally calls something equivalent to JSON.parse() on the response body, so all the same failure modes apply — an empty or truncated body throws exactly the same error whether you call JSON.parse() directly or use the convenience method.
Fixing "Unexpected End of JSON Input"
Fix 1: Check for an empty or missing body before parsing, handling the no-content case explicitly rather than letting the parse throw:
async function safeJsonParse(response: Response) {
const text = await response.text();
if (!text) return null;
return JSON.parse(text);
}
Fix 2: Check the HTTP status code explicitly for responses that legitimately have no body, avoiding the parse attempt entirely for those cases:
const response = await fetch("/api/status");
if (response.status === 204) {
return null;
}
const data = await response.json();
Fix 3: Guard localStorage and similar sources with a null check before parsing, since a missing key returns null, not valid JSON:
const saved = localStorage.getItem("userPrefs");
const prefs = saved ? JSON.parse(saved) : defaultPrefs;
Should You Wrap Every JSON.parse() Call in a Try/Catch?
For any input whose validity you don't fully control — API responses, localStorage, user-uploaded files, environment variables — yes, wrap the parse (or use a helper like the safeJsonParse example above) and handle the failure case explicitly rather than letting it propagate as an uncaught exception. For JSON you constructed yourself with JSON.stringify() immediately before, a try/catch is unnecessary defensive overhead, since that input is guaranteed valid.
Preventing This Error in Production
Check for empty or no-content responses explicitly (by status code or by checking the response text before parsing) rather than assuming every response has a parseable JSON body. Wrap parsing of any externally-sourced JSON (API responses, storage, file uploads) in error handling that degrades gracefully, since an unhandled parse failure on user- or network-originated data will eventually happen in production regardless of how reliable it seems in testing.
If you hit this error, check first whether the source you're parsing could legitimately be empty (a 204 response, a missing storage key) before assuming the JSON itself is malformed — that's the more common real-world cause.