Tutorials Logic, IN info@tutorialslogic.com

JSON.parse Unexpected Token Error: Causes and Fixes

JSON Parsing Boundaries

JSON.parse accepts one complete value under JSON grammar and throws when the text is malformed. Successful parsing does not validate application shape, trust, precision, schema version, or resource limits.

Diagnose the payload origin before editing text, validate parsed values at the boundary, handle precision-sensitive numbers deliberately, limit untrusted payloads, and monitor parser failures separately from schema failures.

What is JSON.parse Error?

The error SyntaxError: Unexpected token in JSON occurs when JSON.parse() receives invalid JSON data. JSON must follow strict formatting rules, and any deviation causes this error.

Failure Causes

  • Parsing non-JSON string (HTML, plain text, etc.)
  • Single quotes instead of double quotes
  • Trailing commas in JSON
  • Undefined or function values in JSON
  • Parsing already-parsed object

Immediate Repair

Immediate Fix: [wrong] Problem - Invalid JSON

Immediate Fix: [wrong] Problem - Invalid JSON
// [wrong] Problem - Invalid JSON
JSON.parse("{'name': 'John'}"); // Single quotes - Error!

// [ok] Solution - Valid JSON with double quotes
JSON.parse('{"name": "John"}'); // Works!

// [ok] Solution - Use try-catch
try {
    const data = JSON.parse(jsonString);
    console.log(data);
} catch (error) {
    console.error('Invalid JSON:', error);
}

Repair Scenarios

  • JSON requires double quotes for strings. Single quotes are not valid JSON.
  • Trying to parse an object that's already a JavaScript object, not a JSON string.
  • JSON doesn't allow trailing commas, unlike JavaScript objects.
  • Trying to parse non-JSON content like HTML error pages or plain text.
  • JSON doesn't support undefined, functions, or other JavaScript-specific types.

Failure: Invalid JSON - single quotes

Failure: Invalid JSON - single quotes
// Invalid JSON - single quotes
const jsonString = "{'name': 'John', 'age': 30}";
JSON.parse(jsonString); // SyntaxError!

// Also invalid - unquoted keys
const jsonString2 = "{name: 'John'}";
JSON.parse(jsonString2); // SyntaxError!

Correction: Valid JSON - double quotes for both keys and values

Correction: Valid JSON - double quotes for both keys and values
// Valid JSON - double quotes for both keys and values
const jsonString = '{"name": "John", "age": 30}';
const data = JSON.parse(jsonString);
console.log(data); // { name: 'John', age: 30 }

// Or use template literals with double quotes inside
const jsonString2 = `{"name": "John", "age": 30}`;
const data2 = JSON.parse(jsonString2);

Failure: Already a JavaScript object

Failure: Already a JavaScript object
// Already a JavaScript object
const user = { name: 'John', age: 30 };
JSON.parse(user); // SyntaxError: Unexpected token o in JSON

// Or from API that already returns object
fetch('/api/user')
    .then(res => res.json()) // Already parsed here
    .then(data => {
        const parsed = JSON.parse(data); // Error! Already an object
    });

Correction: Don't parse if already an object

Correction: Don't parse if already an object
// Don't parse if already an object
const user = { name: 'John', age: 30 };
console.log(user); // Use directly

// Check type before parsing
function safeParse(data) {
    if (typeof data === 'string') {
        return JSON.parse(data);
    }
    return data; // Already an object
}

// With fetch, don't double-parse
fetch('/api/user')
    .then(res => res.json()) // Parse once
    .then(data => {
        console.log(data); // Use directly, don't parse again
    });

Failure: Trailing comma in object

Failure: Trailing comma in object
// Trailing comma in object
const jsonString = '{"name": "John", "age": 30,}';
JSON.parse(jsonString); // SyntaxError!

// Trailing comma in array
const jsonString2 = '["apple", "banana", "orange",]';
JSON.parse(jsonString2); // SyntaxError!

Correction: Remove trailing commas

Correction: Remove trailing commas
// Remove trailing commas
const jsonString = '{"name": "John", "age": 30}'; // No trailing comma
JSON.parse(jsonString); // Works!

const jsonString2 = '["apple", "banana", "orange"]'; // No trailing comma
JSON.parse(jsonString2); // Works!

// Or clean the string before parsing
function cleanJSON(str) {
    return str.replace(/,(\s*[}\]])/g, '$1'); // Remove trailing commas
}

const dirty = '{"name": "John",}';
const clean = cleanJSON(dirty);
JSON.parse(clean); // Works!

Failure: API returns HTML error page instead of JSON

Failure: API returns HTML error page instead of JSON
// API returns HTML error page instead of JSON
fetch('/api/user')
    .then(res => res.json()) // Tries to parse HTML as JSON
    .then(data => console.log(data))
    .catch(err => console.error(err)); // SyntaxError!

// Or plain text response
const response = "User not found";
JSON.parse(response); // SyntaxError!

Correction: Check content type before parsing

Correction: Check content type before parsing
// Check content type before parsing
fetch('/api/user')
    .then(res => {
        const contentType = res.headers.get('content-type');
        if (contentType && contentType.includes('application/json')) {
            return res.json();
        } else {
            return res.text(); // Get as text instead
        }
    })
    .then(data => console.log(data))
    .catch(err => console.error(err));

// Or check if response is OK
fetch('/api/user')
    .then(res => {
        if (!res.ok) {
            throw new Error(`HTTP error! status: ${res.status}`);
        }
        return res.json();
    })
    .then(data => console.log(data))
    .catch(err => console.error(err));

// Use try-catch for manual parsing
function safeParse(str) {
    try {
        return JSON.parse(str);
    } catch (error) {
        console.error('Not valid JSON:', str);
        return null;
    }
}

Failure: Trying to stringify and parse undefined

Failure: Trying to stringify and parse undefined
// Trying to stringify and parse undefined
const obj = { name: 'John', age: undefined };
const jsonString = JSON.stringify(obj); // '{"name":"John"}' - age is omitted
console.log(jsonString);

// Function in object
const obj2 = {
    name: 'John',
    greet: function() { return 'Hello'; }
};
const jsonString2 = JSON.stringify(obj2); // '{"name":"John"}' - function omitted

Correction: Use null instead of undefined

Correction: Use null instead of undefined
// Use null instead of undefined
const obj = { name: 'John', age: null };
const jsonString = JSON.stringify(obj);
const parsed = JSON.parse(jsonString); // Works!

// Remove undefined values before stringifying
function cleanObject(obj) {
    return Object.fromEntries(
        Object.entries(obj).filter(([_, v]) => v !== undefined)
    );
}

const obj2 = { name: 'John', age: undefined, city: 'NYC' };
const clean = cleanObject(obj2);
const jsonString2 = JSON.stringify(clean); // '{"name":"John","city":"NYC"}'

// Use replacer function
const obj3 = { name: 'John', age: undefined };
const jsonString3 = JSON.stringify(obj3, (key, value) => {
    return value === undefined ? null : value;
});

Prevention Practices

  • Always use try-catch - Wrap JSON.parse() in try-catch blocks
  • Validate JSON format - Use double quotes, no trailing commas
  • Check content type - Verify response is JSON before parsing
  • Don't double-parse - Check if data is already an object
  • Use JSON validators - Test JSON with online validators
  • Handle errors gracefully - Provide fallback values
  • Log the input - Console.log the string before parsing for debugging

JSON Grammar and Failure Location

JSON supports objects, arrays, strings, numbers, booleans, and null under a stricter grammar than JavaScript object literals. Property names and strings use double quotes; comments, trailing commas, single-quoted strings, undefined, functions, BigInt literals, and non-finite number literals are not valid JSON.

`JSON.parse` throws SyntaxError when the complete input is not valid JSON. Messages and positions vary by engine, and a reported character can be where parsing became impossible rather than where malformed input began. Preserve a bounded, redacted sample and payload origin before transforming it.

An HTML response, proxy error page, empty body, or truncated transport is often passed to JSON.parse by mistake. Check status, content type, length, and response body origin. With fetch, `response.json()` also rejects when its body cannot be decoded as JSON; it does not make an unsuccessful HTTP status successful.

Do not repair unknown payloads by replacing quotes or removing commas. Such transformations can corrupt legitimate strings and conceal an upstream protocol defect. Fix the producer or use a parser for the actual documented format.

  • Apply JSON grammar rather than JavaScript literal rules.
  • Retain payload origin and a redacted failure sample.
  • Check HTTP status, content type, and body before parsing.
  • Repair the producer instead of guessing text replacements.

Parsing and Reviver Semantics

`JSON.parse(text)` first converts its input to a string, parses one complete JSON value, and returns JavaScript values. Leading and trailing JSON whitespace are permitted, but extra non-whitespace after the value is not. An empty string is not a JSON value.

A reviver walks parsed properties from the leaves toward the root. Returning undefined deletes a property, including possibly the root result. Use a normal function when the reviver needs its holder object as `this`; an arrow does not receive that dynamic binding.

Revivers can normalize dates, tagged values, or legacy fields, but they run after parsing and do not make malformed JSON valid. Keep transformations schema-specific and avoid converting every date-looking string or numeric-looking key. Ambiguous heuristics create silent data changes.

Parsing numbers uses JavaScript Number semantics. Large integers can lose precision before a reviver sees the numeric value. Encode precision-sensitive identifiers or integers as strings under a documented schema and convert them deliberately to BigInt or a decimal representation after validation.

  • Parse exactly one complete JSON value.
  • Remember that reviver can delete properties and the root.
  • Keep revival rules explicit and schema-specific.
  • Represent precision-sensitive numbers without lossy parsing.

Validation and Versioning

Successful parsing proves syntax, not application shape. The result may be null, an array instead of an object, or an object with missing and wrongly typed fields. Validate at the boundary before accessing nested data or passing it into trusted domain code.

Define required fields, optional fields, allowed values, collection limits, string lengths, and unknown-field policy. Return diagnostics with safe field paths and categories. Avoid echoing secret values in validation errors, logs, or user messages.

Version long-lived stored or exchanged data. Migrate known older versions through explicit steps, reject unsupported future versions, and preserve rollback expectations. Clearing local storage is not a production migration strategy, and silently defaulting every missing field can mask incompatible releases.

Model success and validation failure as distinct results. A valid empty payload should remain distinguishable from malformed input, permission failure, not found, and network error. This lets callers select fallback, repair, retry, or user messaging correctly.

  • Validate shape and limits after successful parsing.
  • Report safe field paths without leaking values.
  • Version persisted and exchanged schemas.
  • Keep empty, malformed, missing, and failed outcomes distinct.

Security and Resource Limits

Parsed JSON is untrusted data. Do not merge arbitrary keys into configuration, class instances, or behavior-bearing objects. Select allowed properties into a new null-prototype or domain object and reject dangerous or unknown keys according to the schema.

Parsing a very large or deeply nested payload can consume CPU and memory before application validation runs. Enforce transport size limits, collection counts, nesting policy where possible, and timeouts at the server or gateway. Client code should also avoid retaining both huge source text and transformed copies unnecessarily.

JSON data is not safe HTML. Insert strings with textContent and apply context-specific validation to URLs and attributes. Likewise, do not construct SQL, shell commands, regular expressions, or source code from parsed fields without the correct structured API and policy.

Do not log complete malformed payloads by default. Record request ID, producer, schema version, content type, length, hash or bounded sample, and parser category. Redact credentials, personal data, session material, and nested tokens before telemetry leaves the process.

  • Copy only allowed fields into trusted objects.
  • Bound payload size, nesting, and collection counts.
  • Apply output-context safety after parsing.
  • Keep malformed-payload telemetry minimal and redacted.

JSON Tests and Operations

Test valid objects, arrays, scalar roots, null, empty input, truncated input, trailing commas, invalid escapes, duplicate keys according to policy, large integers, unknown fields, old versions, and maximum allowed sizes. Use fixtures produced by the real integration where possible.

Round-trip tests are useful only for values JSON can represent and for the intended normalization. Undefined object properties are omitted, unsupported array values become null in common stringification cases, dates usually serialize as strings, and object identity or prototypes are not preserved.

For network clients, test successful JSON, non-JSON error bodies, no-content responses, wrong content type, compressed or truncated transport, and cancellation. Parse according to the endpoint contract rather than calling response.json for every status.

Track parse and validation failures separately by producer and schema version. A spike in SyntaxError indicates transport or serialization trouble; a spike in schema rejection indicates a compatible-grammar contract mismatch. Alerting on those categories directs ownership to the right system.

  • Cover grammar, schema, version, and resource boundaries.
  • Limit round-trip expectations to JSON-representable semantics.
  • Test non-JSON and empty HTTP responses.
  • Separate parse failures from validation failures in monitoring.

JSON Failure Examples

Safely Parse a Fetch Response

Safely Parse a Fetch Response
async function readJson(response) {
  const contentType = response.headers.get("content-type") || "";
  const raw = await response.text();

  if (!response.ok) {
    throw new Error(`HTTP ${response.status}: ${raw.slice(0, 80)}`);
  }

  if (!contentType.includes("application/json")) {
    throw new Error(`Expected JSON, received ${contentType || "unknown type"}`);
  }

  if (!raw.trim()) {
    return null;
  }

  return JSON.parse(raw);
}
  • Reading text first preserves the body for useful diagnostics.
  • Unexpected token < commonly indicates an HTML login, proxy, or server error page.

Avoid Double Parsing and Invalid JSON Syntax

Avoid Double Parsing and Invalid JSON Syntax
const validJson = '{"name":"Maya","roles":["editor"]}';
const parsed = JSON.parse(validJson);
console.log(parsed.name);

// `parsed` is already an object. Use it directly.
console.log(parsed.roles[0]);

// Invalid JSON examples:
// {'name':'Maya'}       single quotes
// {"name":"Maya",}     trailing comma
// {"value": undefined} unsupported value
  • Call response.json() or JSON.parse(), not both on the same value.
  • Use JSON.stringify when converting a JavaScript value into JSON text.
Before you move on

JSON.parse Unexpected Token Error: Causes and Fixes Mastery Check

6 checks
  • Verify status, content type, body origin, and complete JSON grammar.
  • Validate shape, types, limits, and schema version after parsing.
  • Encode large precision-sensitive numbers as strings.
  • Copy only allowed keys into trusted domain objects.
  • Confirm the parsed root type matches the endpoint contract.
  • Test malformed, truncated, empty, old, and oversized payloads.

JavaScript Questions Learners Ask

JSON.parse() throws an error when the input string is not valid JSON. Common causes include single quotes instead of double quotes, trailing commas, parsing already-parsed objects, or trying to parse HTML/plain text.

Use double quotes for all strings, remove trailing commas, wrap in try-catch, check if data is already an object, and validate the JSON format before parsing.

JSON specification requires double quotes for strings. Single quotes are not valid JSON, even though they work in JavaScript objects. Always use double quotes in JSON.

Browse Free Tutorials

Explore 500+ free tutorials across 20+ languages and frameworks.