SyntaxError: Unexpected end of input means JavaScript reached the end of your code or data but was still expecting more. The parser opened something (a function, an object, a string) and never found the closing character it needed.
This error appears in two common scenarios: incomplete JavaScript code with missing brackets or quotes, and JSON.parse() receiving empty or truncated data. The first is typically a development-time bug, while the second often surfaces in production when API responses fail.
The Problem
The JavaScript parser reads your code character by character, tracking opening and closing delimiters. When it reaches the end of the input while still waiting for a closing }, ], ), or quote, it throws this error.
Code syntax variant:
function calculateTotal(items) {
let total = 0;
items.forEach(item => {
total += item.price;
// Missing closing brace for forEach
// Missing closing brace for function
// SyntaxError: Unexpected end of input
JSON parsing variant:
// Server returned empty response
const response = await fetch('/api/data');
const data = await response.json();
// SyntaxError: Unexpected end of JSON input
The JSON variant shows as Unexpected end of JSON input and occurs when JSON.parse() (or response.json()) receives an empty string, truncated data, or non-JSON content.
Understanding the Root Cause
“Unexpected end of input” stems from different scenarios depending on whether you’re dealing with code syntax or JSON parsing:
1. Missing Closing Brackets or Braces
Most common during development: Forgetting to close a function, object, array, or block statement leaves the parser expecting more input.
How to identify: The error points to the end of your file or code block. Check for mismatched { }, [ ], or ( ) pairs.
2. Unclosed Strings or Template Literals
Starting a string with a quote or backtick and not providing the closing delimiter creates an unterminated string.
How to identify: Look for strings that span multiple lines unexpectedly or missing closing quotes.
3. Empty API Responses
Servers sometimes return empty responses (status 204, empty body with 200, or error conditions) when your code expects JSON data.
How to identify: Check the Network tab in DevTools. Look for responses with empty bodies or non-JSON content types.
4. Server Returning HTML Instead of JSON
When servers encounter errors, they often return HTML error pages instead of JSON. Your code tries to parse <!DOCTYPE html> as JSON and fails.
How to identify: Inspect the response body in DevTools. If you see HTML when expecting JSON, the server returned an error page.
5. Truncated Network Responses
Network interruptions, CDN issues, or proxy problems can cut off responses mid-transmission, leaving incomplete JSON.
How to identify: Responses that look like valid JSON but end abruptly, often in the middle of a string or object.
6. Parsing Already-Parsed Data
Calling JSON.parse() on data that’s already a JavaScript object (not a JSON string) throws this error.
How to identify: Log the value and its type before parsing. If it’s already an object, you don’t need to parse it.
How to Fix “Unexpected end of input”
Troubleshooting Checklist
- Check DevTools console for the line number where parsing stopped
- Verify all opening brackets have matching closing brackets
- Inspect API responses in the Network tab before parsing
- Confirm the server returns
application/jsoncontent type - Test what happens when the server returns an error or empty response
- Wrap JSON parsing in try/catch blocks
Step 1: Fix Code Syntax Issues
For development-time syntax errors, use your editor’s bracket matching:
// Use an editor with bracket matching to find mismatches
// VSCode: Cmd+Shift+P -> "Go to Bracket"
// Most editors highlight matching brackets when cursor is on one
// Before: Missing closures
function processData(items) {
return items.map(item => {
return {
id: item.id,
name: item.name
// missing } for object
// missing } for arrow function
// missing } for function
// After: All brackets matched
function processData(items) {
return items.map(item => {
return {
id: item.id,
name: item.name
};
});
}
Run your code through a linter like ESLint to catch these errors before they reach production.
Step 2: Validate Responses Before Parsing
Check that you have valid JSON before attempting to parse:
async function fetchData(url) {
const response = await fetch(url);
// Check if response is OK
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
// Check content type
const contentType = response.headers.get('content-type');
if (!contentType?.includes('application/json')) {
const text = await response.text();
throw new Error(`Expected JSON, got ${contentType}: ${text.slice(0, 100)}`);
}
// Now safe to parse
return response.json();
}
Step 3: Handle Empty Responses
Some endpoints legitimately return empty responses. Handle this gracefully:
async function fetchWithEmptyHandling(url) {
const response = await fetch(url);
// Handle 204 No Content
if (response.status === 204) {
return null;
}
// Check for empty body
const text = await response.text();
if (!text || text.trim() === '') {
return null;
}
// Parse the JSON
try {
return JSON.parse(text);
} catch (error) {
console.error('Failed to parse response:', text.slice(0, 200));
throw error;
}
}
Step 4: Wrap JSON.parse in Try/Catch
Always protect JSON parsing with error handling:
function safeJsonParse(jsonString, fallback = null) {
// Handle empty or falsy input
if (!jsonString || typeof jsonString !== 'string') {
return fallback;
}
try {
return JSON.parse(jsonString);
} catch (error) {
console.error('JSON parse failed:', error.message);
console.error('Input was:', jsonString.slice(0, 100));
return fallback;
}
}
// Usage
const data = safeJsonParse(localStorage.getItem('userData'), {});
Step 5: Debug Server Responses
When the error occurs in production, you need visibility into what the server actually returned:
async function debuggableFetch(url, options = {}) {
try {
const response = await fetch(url, options);
const text = await response.text();
// Log response details for debugging
console.log('Response status:', response.status);
console.log('Content-Type:', response.headers.get('content-type'));
console.log('Body length:', text.length);
if (!text) {
console.warn('Empty response body from:', url);
return null;
}
return JSON.parse(text);
} catch (error) {
console.error('Fetch/parse error for', url, error);
throw error;
}
}
Step 6: Monitor JSON Parsing Errors in Production
This isn’t an error you’ll catch in development if it’s caused by intermittent server issues or network problems. Production error monitoring captures these failures with the context you need: what URL was requested, what the response looked like, and what the user was doing when it happened.
Track patterns like specific endpoints that return empty responses, times of day when truncation occurs, or user segments affected by server errors.
When to Investigate This Error
“Unexpected end of input” errors deserve different responses depending on the cause:
Investigate immediately:
- JSON parsing errors in production affecting user functionality
- Errors that correlate with specific API endpoints
- Sudden spikes after deployments or infrastructure changes
- Errors affecting checkout, authentication, or data submission
Development-time fixes:
- Syntax errors from missing brackets (fix before committing)
- Template literal or string issues (your linter should catch these)
May be acceptable:
- Occasional parsing failures from unstable third-party APIs
- Errors from API responses you can gracefully handle with fallbacks
Summary
Unexpected end of input means the JavaScript parser expected more code or data than it received. For syntax errors, check for missing closing brackets, braces, and quotes. For JSON errors, validate responses before parsing and handle empty or malformed data gracefully.
The JSON parsing variant is particularly sneaky because it only appears when servers misbehave, which often means production-only bugs. Build defensive parsing that expects things to go wrong, and monitor for patterns that indicate server-side issues.