JavaScript JSON.parse() Errors: What They Mean and How to Fix Them
SyntaxError: Unexpected token? JSON.parse() failing? This guide explains every JavaScript JSON parse error with examples and fixes.
Have broken JSON right now? Fix it free in under 1 second — no signup.
Fix My JSON →JSON.parse() is one of the most-called functions in any JavaScript application that talks to an API or processes AI output. When it throws, the error message is notoriously unhelpful: SyntaxError: Unexpected token. This guide explains every failure mode, what the errors actually mean, and how to write defensive parsing code that doesn't crash your application.
How JSON.parse() Works
JSON.parse() takes a string and returns a JavaScript value. It is synchronous, strict, and implements the JSON spec with no extensions. Unlike JavaScript itself — which permits trailing commas and comments via tools like Babel — JSON.parse() will reject them unconditionally.
JSON.parse('{"name": "Alice"}') // {name: 'Alice'}
JSON.parse('{"name": "Alice",}') // SyntaxError
JSON.parse("{'name': 'Alice'}") // SyntaxError
JSON.parse('undefined') // SyntaxError
JSON.parse(undefined) // SyntaxError (not a string)
JSON.parse(null) // SyntaxError
When it fails, it throws a SyntaxError. In modern V8 (Node.js 20+, Chrome 90+), the message has improved significantly, but in older environments you get very little context.
Every Common SyntaxError, Explained
1. Unexpected token '}' (or ']')
What it means: The parser found a closing bracket but wasn't expecting one. The most common cause is a trailing comma.
{
"items": [1, 2, 3,]
}
The comma after 3 makes the parser expect another value before the ]. When it finds ] instead, it throws.
2. Unexpected token ''' (apostrophe)
What it means: Single-quoted strings. JSON requires double quotes for all strings — both keys and values.
JSON.parse("{'name': 'Alice'}") // SyntaxError: Unexpected token '
This appears frequently when JavaScript object literals (which allow single quotes) are serialized to a string directly rather than through JSON.stringify().
3. Unexpected token 'T' or Unexpected token 'u'
What it means: The string begins with something other than {, [, ", a digit, t (for true), f (for false), or n (for null). The capital T is the start of True (Python boolean), u is often undefined.
JSON.parse("True") // SyntaxError
JSON.parse("undefined") // SyntaxError
JSON.parse("NaN") // SyntaxError
undefined and NaN are JavaScript values, not JSON values. Never use them in data that will be serialized.
4. Unexpected end of JSON input
What it means: The string ended before the JSON structure was complete. Either a truncated response (streaming, network cutoff) or a completely empty string.
JSON.parse("") // SyntaxError: Unexpected end of JSON input
JSON.parse('{"name":') // SyntaxError: Unexpected end of JSON input
JSON.parse('[1, 2,') // SyntaxError: Unexpected end of JSON input
This is the most common error when consuming streaming AI output.
5. Unexpected non-whitespace character after JSON data
What it means: Valid JSON was found and parsed, but there's extra content after it. Markdown code fences are the most common culprit.
JSON.parse('{"name": "Alice"}\n') // SyntaxError
When an AI model wraps JSON in triple backticks, the trailing
causes this error.
6. Expected double-quoted property name in JSON
What it means: An object key is unquoted.
JSON.parse('{name: "Alice"}') // SyntaxError
JavaScript allows unquoted keys in object literals, but JSON does not.
Handling fetch() and axios Responses
fetch()
A common mistake with fetch() is calling JSON.parse() on the Response object itself or calling .json() twice:
// Wrong: response is a Response object, not a string
const response = await fetch('/api/data')
const data = JSON.parse(response) // TypeError
// Wrong: .json() is already parsing
const data = JSON.parse(await response.json()) // SyntaxError (parsing an object)
// Correct: use .json() OR parse .text()
const data = await response.json()
// Correct alternative if you need to inspect the raw string first
const text = await response.text()
console.log(text) // debug what the server actually returned
const data = JSON.parse(text)
Always check the response status before parsing:
async function fetchJSON(url) {
const response = await fetch(url)
if (!response.ok) {
throw new Error(HTTP ${response.status}: ${response.statusText})
}
const contentType = response.headers.get('content-type')
if (!contentType?.includes('application/json')) {
const text = await response.text()
throw new Error(Expected JSON but got: ${text.slice(0, 200)})
}
return response.json()
}
axios
Axios automatically parses JSON responses when the Content-Type is application/json. Calling JSON.parse() on response.data will throw because response.data is already an object, not a string.
// Wrong
const { data } = await axios.get('/api/data')
const parsed = JSON.parse(data) // Error: data is already an object
// Correct
const { data } = await axios.get('/api/data')
// data is already parsed
If an API returns JSON with the wrong Content-Type header, tell axios explicitly:
const { data } = await axios.get('/api/data', {
transformResponse: [(raw) => {
try {
return JSON.parse(raw)
} catch {
return raw // return raw string if not valid JSON
}
}]
})
Dealing with AI-Generated JSON in Frontend Apps
When you're calling an AI API (OpenAI, Anthropic, Gemini) and the model returns structured output as text, the response often has issues.
Stripping Markdown Fences
function extractJSON(text) {
// Handle
json ... `` and ` ... const fenceMatch = text.match(/
(?:json)?\s\n?([\s\S]?)\n?``/)
if (fenceMatch) return fenceMatch[1].trim()
// Handle inline backticks: {...}
const inlineMatch = text.match(/([^]+)`/)
if (inlineMatch) return inlineMatch[1].trim()
return text.trim()
}
const raw = '``json\n{"name": "Alice"}\n``'
const data = JSON.parse(extractJSON(raw))
Removing Trailing Commas
javascript
function removeTrailingCommas(str) {
// This simple version doesn't handle commas inside strings safely
// Use aijsonmedic.com for production-grade repair
return str.replace(/,\s*([}\]])/g, '$1')
}
For a robust, production-safe solution that handles edge cases (commas inside string values, nested structures), use the JSON Fixer to repair the JSON before deploying.
Safe Parsing Patterns
Basic try/catch
javascript
function safeParseJSON(text, fallback = null) {
try {
return JSON.parse(text)
} catch (err) {
console.warn('JSON.parse failed:', err.message)
return fallback
}
}
With Type Guard
javascript
function isRecord(value) {
return typeof value === 'object' && value !== null && !Array.isArray(value)
}
function parseAsRecord(text) {
try {
const parsed = JSON.parse(text)
if (!isRecord(parsed)) {
throw new TypeError(Expected object, got ${typeof parsed})
}
return parsed
} catch (err) {
throw new Error(Invalid JSON object: ${err.message})
}
}
With Zod Validation
For TypeScript projects, Zod gives you parse + validate in one step:
typescript
import { z } from 'zod'
const UserSchema = z.object({
name: z.string(),
age: z.number().int().positive(),
email: z.string().email()
})
function parseUser(text: string) {
const raw = JSON.parse(text) // throws SyntaxError if invalid JSON
return UserSchema.parse(raw) // throws ZodError if wrong shape
}
Use the JSON Validator to check your JSON structure interactively before writing schema code.
JSON5 and When to Consider It
JSON5 is a superset of JSON that allows:
- Trailing commas
- Single-quoted strings
- Unquoted keys
- Comments
- Multi-line strings
javascriptimport JSON5 from 'json5'
JSON5.parse("{ name: 'Alice', age: 30, }") // works
Consider JSON5 when:
- You control both the writer and the reader (e.g., config files)
- The output is always from a human or a system you own
Do not use JSON5 as a crutch for AI output — the right fix is to prompt the AI to return valid JSON, then validate it. Use the JSON Fixer to repair existing invalid responses rather than adopting a non-standard parser.
The Double-Stringify Trap
One of the most disorienting bugs: JSON.parse() returns a string instead of an object.
javascript
const data = { name: 'Alice' }
const stringifiedOnce = JSON.stringify(data) // '{"name":"Alice"}'
const stringifiedTwice = JSON.stringify(stringifiedOnce) // '"{\\"name\\":\\"Alice\\"}"'
// Now parsing once still gives a string
const result = JSON.parse(stringifiedTwice) // '{"name":"Alice"}' — still a string!
typeof result // 'string'
// You'd need to parse again
const actual = JSON.parse(result) // {name: 'Alice'}
This happens when:
- A server
JSON.stringify()s data before inserting it into a JSON response body - A storage layer (Redis, localStorage) serializes a value that's already a JSON string
- A middleware double-encodes a response
Diagnosis: If typeof JSON.parse(text) === 'string', you have double-encoded JSON. Parse once more.
Using the JSON.parse() Reviver
JSON.parse() accepts an optional second argument — a reviver function — that transforms values during parsing. Useful for date strings:javascript
function dateReviver(key, value) {
const iso8601 = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/
if (typeof value === 'string' && iso8601.test(value)) {
return new Date(value)
}
return value
}
const data = JSON.parse('{"created": "2026-05-08T12:00:00Z"}', dateReviver)
data.created instanceof Date // true
Quick Diagnostic Checklist
When JSON.parse() throws, ask these questions in order:
- Is the input a string? —
typeof input === 'string' - Is it empty? —
input.trim() === '' - Does it start with a backtick? — Markdown fence, use
extractJSON() - Does it start with
{ or [? — If not, check for leading prose from an AI - Does it end cleanly? —
input.trim() ending in } or ] - Paste into the JSON Fixer — get a full repair report in one click
For more complex issues like validating the parsed structure, try the JSON Validator. To pretty-print before debugging, use the JSON Formatter. To compare two versions of a response, use the JSON Diff Tool. For a full breakdown of repair tools available in 2026, see Best JSON Repair Tools 2026. To integrate automated JSON repair directly into your application or pipeline, the JSON Repair API accepts broken JSON via POST and returns fixed JSON with no authentication required.
FAQ
What does "SyntaxError: Unexpected token" mean in JSON.parse?
It means the parser encountered a character it didn't expect at that position. The character after "token" tells you what was found: Unexpected token ' means single quotes were used instead of double quotes. Unexpected token u usually means undefined was passed as a string. Unexpected token < means HTML was returned (the response is an error page, not JSON). The character position in the error points to the exact location.
How do I safely parse JSON in JavaScript without crashing the app?
Wrap JSON.parse() in a try/catch and return a default value on failure:
javascript
function safeParse(str, fallback = null) {
try { return JSON.parse(str); }
catch { return fallback; }
}
```
For TypeScript, use an unknown type to force type narrowing before use: const data: unknown = JSON.parse(str).
Why does fetch().json() throw when the status is 200?
response.json() throws if the response body is not valid JSON — regardless of the status code. A server can return HTTP 200 with an HTML body (common for catch-all error pages or CDN error responses). Check response.headers.get('content-type') before calling .json(). If it doesn't include application/json, the body is not JSON.
How do I parse JSON that has JavaScript comments in it?
JSON.parse() will throw on any comment. Use the json5 library (npm install json5) which parses JSON5 format (a superset that allows comments), or strip comments first with a regex: /\/\/[^\n]/g for line comments and /\/\[\s\S]?\\//g for block comments. Or use the JSON Fixer which strips comments automatically.
What is the safest way to handle AI-generated JSON in production?
Validate first with JSON.parse() in a try/catch. If it throws, run the output through a repair library (jsonrepair in JS, json-repair in Python) before retrying the parse. Log failures with the raw LLM output for debugging. Set response_format: { type: "json_object" } in OpenAI's API to reduce the frequency of malformed output at the source.
Still dealing with broken JSON?
Paste it in and get it fixed in under 1 second — free, no signup, no install. Works with ChatGPT, Claude, n8n, and any AI output.
Fix My JSON Free →Related Articles