{ }jsonkitOpen

How to fix JSON syntax errors and JSON.parse SyntaxError

15 min read · updated 2026-10-01

To fix a JSON syntax error, you need to find the character the parser could not match to the JSON grammar. The error message often points to where parsing *failed*, not where you made the mistake. A missing comma on line 12 can show up as an error on line 14.

JSON is defined by RFC 8259, and the standard is strict. No trailing commas, no comments, and only double-quoted keys and strings. Most errors come from writing JSON as if it were JavaScript or Python. This guide lists the errors you will hit, including the exact SyntaxError text JSON.parse throws in each browser, with the fix for each. It also explains the line and column numbers parsers report.

What counts as a JSON syntax error

JSON has a small, strict grammar. A document is a single value: an object, an array, a string, a number, true, false or null. Objects hold comma-separated "key": value pairs inside braces. Arrays hold comma-separated values inside brackets. Anything outside that grammar is a syntax error, even if it looks fine to a person.

RFC 8259 leaves no room for ambiguity, so a valid JSON document parses the same way in every conforming library. That makes the format reliable for APIs and config files. It is also why the parser won't guess what you meant.

  • Keys and string values must use double quotes ("), never single quotes or backticks.
  • No trailing comma after the last element of an object or array.
  • No comments of any kind (// or /* */).
  • No unquoted keys, and no leading zeros or NaN/Infinity in numbers.
  • The document must contain exactly one top-level value, with nothing after it.

How to read line and column error messages

Every parser reports a position, but the format differs by engine. For JSON.parse in JavaScript:

  • Older V8 (Chrome, Node.js) said "Unexpected token } in JSON at position 27".
  • Recent V8 says "Expected double-quoted property name in JSON at position 27" and adds the line and column.
  • Firefox reports "at line 1 column 28 of the JSON data".
  • Safari names the problem but gives no position.

V8 positions are zero-based character offsets. Line and column numbers are one-based. Python's json module reports line, column and character offset. In every case, the number marks where the parser *stopped*, usually the first character it could not accept.

The mistake is often just before that point. The parser only notices a missing comma when it reaches the next key, so the reported column lands on that key, not on the gap where the comma belongs. Read one token back from the reported position.

Python's JSONDecodeError exposes line, column and offset.python
import json

data = '{"name": "Ada", "age": 36,}'
try:
    json.loads(data)
except json.JSONDecodeError as e:
    print(f"{e.msg} at line {e.lineno} column {e.colno} (char {e.pos})")

# Python 3.12 and earlier:
# Expecting property name enclosed in double quotes at line 1 column 27 (char 26)
# Python 3.13 and later:
# Illegal trailing comma before end of object at line 1 column 26 (char 25)

Here the trailing comma after 36 sits at column 26. Older Python versions report column 27, because the parser expected another key and found }. When a parser says it wanted a property name, the comma before that spot is usually the extra one. Newer versions name the trailing comma and point at it.

Common JSON syntax errors and how to fix them

Most JSON syntax errors fall into a few categories, and nearly all come from treating JSON like JavaScript or Python. Here is a quick-reference table, followed by the fixes that need more explanation.

MistakeInvalidValid
Trailing comma[1, 2, 3,][1, 2, 3]
Single quotes{'id': 1}{"id": 1}
Unquoted key{id: 1}{"id": 1}
Comment{"a": 1 // note}{"a": 1}
Missing comma{"a": 1 "b": 2}{"a": 1, "b": 2}
Leading zero{"n": 007}{"n": 7}
Undefined / NaN{"n": NaN}{"n": null}
Trailing content{"a": 1} extra{"a": 1}

Trailing commas

This is the most common error. JavaScript, Python and most editors accept a comma after the last element. JSON does not. Deleting one is easy, but they hide in deeply nested structures. Reformatting the document makes them easier to spot.

Single quotes and unquoted keys

JSON only accepts double quotes, for both keys and string values. Objects copied from JavaScript source or a Python dict repr use single quotes or bare identifiers, so you need to convert them. Python's str(dict) also writes True, False and None, which are not valid JSON. Use json.dumps instead, as covered in Working with JSON in Python.

Comments

JSON has no comment syntax. If a config parser accepted // comments, it was parsing JSONC, not JSON. Remove comments before you pass the text to a strict parser.

A corrected document after fixing quotes, commas and a comment.json
{
  "id": 1,
  "name": "Ada Lovelace",
  "active": true,
  "roles": ["admin", "editor"],
  "score": 7,
  "manager": null
}

What "Unexpected token" and "Unexpected end of input" mean

These two messages cause most JSON.parse failures in JavaScript, and they mean opposite things. Recent V8 versions word them differently (for example, "Expected ',' or '}' after property value"), but the distinction is the same.

Unexpected token

The parser found a character that is not allowed where it is. Common causes are a stray comma, a single quote, an unquoted word like undefined, or an HTML error page (which starts with <) that your server returned instead of JSON. "Unexpected token < in JSON at position 0" almost always means the response was HTML. Check the raw response before you blame the parser.

Unexpected end of input

The parser reached the end of the string while it was still waiting for an open brace, bracket or quote to close. Either the document was cut off or a closing character is missing. You also get this when you call JSON.parse("") on an empty body, which throws "Unexpected end of JSON input."

A small wrapper that turns parse failures into inspectable results.js
function parseJson(text) {
  try {
    return { ok: true, value: JSON.parse(text) };
  } catch (err) {
    return { ok: false, error: err.message };
  }
}

console.log(parseJson('{"a": 1,}')); // trailing comma: fails to parse
console.log(parseJson('{"a": 1'));   // unclosed object: fails to parse
console.log(parseJson('{"a": 1}'));  // { ok: true, value: { a: 1 } }

Fixes for each JSON.parse error message

Here is each common JSON.parse message on its own, with the exact text current Chrome, Edge and Node.js print, what causes it and how to fix it. Older V8 versions printed the shorter Unexpected token X in JSON at position N form, which is listed where it differs.

"Unexpected token < in JSON at position 0"

Current V8 wording: Unexpected token '<', "<!DOCTYPE "... is not valid JSON. The text starts with <, so it is HTML, not JSON. The server sent an error page, a login redirect, a 404 page or a single-page app's index.html fallback.

Check the status and Content-Type before parsing a fetch response.js
const res = await fetch("/api/user")
if (!res.ok || !res.headers.get("content-type")?.includes("application/json")) {
  const body = await res.text()
  throw new Error(`Expected JSON, got ${res.status}: ${body.slice(0, 100)}`)
}
const user = await res.json()

Fix the request (wrong URL, missing auth, wrong base path) rather than the parser. The JSON was never there.

"Unexpected end of JSON input"

The parser ran out of text before the document was complete. The usual cause is an empty string: JSON.parse(""), a 204 No Content response passed to response.json(), or a file that was never written. Check for empty text before parsing, or treat an empty body as no data.

Treat an empty body as null instead of parsing it.js
const text = await res.text()
const data = text ? JSON.parse(text) : null

A document cut off in the middle, such as {"a": 1, usually gets a different message in current V8: Expected ',' or '}' after property value. Both mean the same thing. Make sure the whole payload arrived, and look for a missing closing } or ].

"Unexpected token u in JSON at position 0"

Current V8 wording: "undefined" is not valid JSON. You called JSON.parse(undefined). JavaScript turned undefined into the string "undefined", and the parser stopped at the u. It happens when a variable, an object property or localStorage.getItem returns nothing.

Only parse a value that exists.js
const raw = localStorage.getItem("settings")
const settings = raw ? JSON.parse(raw) : {}

"Unexpected token o in JSON at position 1"

Current V8 wording: "[object Object]" is not valid JSON. You passed an object, not a string. JavaScript converted it to the text [object Object], and the parser choked on the o. The data was already parsed, often because response.json() or a library like axios did it for you. Remove the extra JSON.parse.

"Expected property name or '}' in JSON at position N"

A key is not wrapped in double quotes, as in {'name': 'Ada'} or {name: "Ada"}. This text usually comes from a JavaScript object literal or from Python's str(dict). Quote every key and string with double quotes, or generate the text with JSON.stringify or json.dumps.

Keys and strings need double quotes.json
{"name": "Ada"}

"Expected double-quoted property name in JSON at position N"

There is a trailing comma before a closing brace, as in {"a": 1,}. After a comma the parser expects another key, finds } instead, and stops there. Delete the last comma. In an array, the same mistake ([1, 2,]) is reported as Unexpected token ']'.

"Expected ',' or '}' after property value in JSON at position N"

The parser finished a value and found something other than a comma or the end of the object. Either a comma is missing between two properties, a string contains an unescaped double quote that ended it early, or the text was cut off. Arrays get the matching message, Expected ',' or ']' after array element.

Add the missing comma and escape inner quotes.json
{
  "title": "She said \"hi\"",
  "count": 2
}

"Unexpected non-whitespace character after JSON at position N"

A complete JSON value is followed by more text. Two objects back to back, an NDJSON file parsed as one document, or a stray character after the last } all cause it. Parse each line on its own for NDJSON, or remove the extra text.

Parse NDJSON one line at a time.js
const records = ndjson.split("\n").filter(Boolean).map((line) => JSON.parse(line))

"Bad control character in string literal in JSON at position N"

A string contains a raw line break, tab or other control character. JSON strings must escape them as \n, \t or \u00XX. This happens when JSON is built by string concatenation. Build the object in code and serialize it with JSON.stringify, which escapes everything correctly.

"Unexpected number in JSON" and "Unexpected token" with a letter

Unexpected number usually means a number with a leading zero, such as 007, which JSON does not allow. Unexpected token followed by a letter means a bare word the grammar does not know, such as NaN, Infinity, True, None or a misspelled tru. Use 7, null, true or false instead.

Python: "Expecting value: line 1 column 1 (char 0)"

Python's version of an empty or non-JSON body. json.loads(""), an HTML error page or an empty HTTP response all raise it. Print response.status_code and response.text first, and only call response.json() when the body really is JSON.

JSON ValidatorPaste the failing text to see the line and column of the first error.→

JSON.parse SyntaxError messages by browser and runtime

Each engine words the same mistake differently, so a search for an error message often finds advice for another runtime. The tables below map the messages you will see to their cause and fix. Each one is a SyntaxError thrown by JSON.parse (or a JSONDecodeError in Python). N is the reported position.

Chrome, Edge and Node.js (V8)

Current V8 versions add the text that failed ("... is not valid JSON") or a line and column to the message. Older versions (before about Chrome 114 and Node.js 20) used the shorter "Unexpected token X in JSON at position N" form for almost everything.

MessageCauseFix
Unexpected token '<', "<!DOCTYPE "... is not valid JSONThe response is an HTML page, such as a 404, 500, login redirect or SPA fallback. Older V8: Unexpected token < in JSON at position 0.Check response.ok and the Content-Type header before calling response.json(), and log the raw body.
"undefined" is not valid JSONJSON.parse(undefined). A missing variable, property or storage value was passed in. Older V8: Unexpected token u in JSON at position 0.Guard the input: only parse when the value is a string, and fall back to a default otherwise.
"[object Object]" is not valid JSONAn object was passed to JSON.parse, so it was converted to the string [object Object] first. Usually the data was already parsed.Drop the extra JSON.parse, or JSON.stringify the object when storing it.
Unexpected end of JSON inputThe text is empty or cut off before a closing }, ] or quote. A 204 No Content response or a truncated file can cause this.Check for an empty body before parsing, and make sure the whole payload arrived.
Expected property name or '}' in JSON at position NA key is single-quoted or unquoted, as in {'a': 1} or {a: 1}.Wrap every key in double quotes.
Expected double-quoted property name in JSON at position NA trailing comma before }, as in {"a": 1,}.Delete the comma after the last property.
Expected ',' or '}' after property value in JSON at position NA missing comma between properties, or an unescaped " ending a string early.Add the comma, or escape the inner quote as \".
Unexpected non-whitespace character after JSON at position NExtra content after a complete value. Two documents back to back, NDJSON parsed as one document, or a stray character.Parse one document at a time (split NDJSON by line) or remove the trailing text.
Bad control character in string literal in JSON at position NA raw newline, tab or other control character inside a string.Escape it as \n, \t or \u00XX, ideally by generating the JSON with JSON.stringify.

Firefox (SpiderMonkey)

Firefox starts every message with JSON.parse: and ends it with at line L column C of the JSON data, so the location is easy to find.

MessageCauseFix
JSON.parse: unexpected character at line 1 column 1 of the JSON dataThe text does not start with a JSON value. It is usually HTML, undefined or plain text.Inspect the raw response and check that the endpoint returns JSON.
JSON.parse: expected property name or '}'Single-quoted or unquoted key.Use double-quoted keys.
JSON.parse: expected double-quoted property nameTrailing comma before }.Remove the trailing comma.
JSON.parse: unexpected end of dataEmpty or truncated input.Check for an empty body and make sure the payload is complete.
JSON.parse: unexpected non-whitespace character after JSON dataExtra content after the first complete value.Parse each document separately or remove the extra text.
JSON.parse: bad control character in string literalRaw newline or tab inside a string.Escape the character.

Safari (JavaScriptCore)

Safari's messages start with JSON Parse error: and include no position. Paste the text into a validator to find the line and column.

MessageCauseFix
JSON Parse error: Unrecognized token '<'HTML instead of JSON.Check the response status and body.
JSON Parse error: Unexpected identifier "undefined"JSON.parse(undefined).Guard the input before parsing.
JSON Parse error: Unexpected EOFEmpty or truncated input.Check for an empty body.
JSON Parse error: Single quotes (') are not allowed in JSONSingle-quoted key or string.Switch to double quotes.
JSON Parse error: Property name must be a string literalTrailing comma before }, or an unquoted key.Remove the comma or quote the key.

Python (json.decoder.JSONDecodeError)

Python's json.loads and json.load raise json.decoder.JSONDecodeError (also available as json.JSONDecodeError). It is a subclass of ValueError, and the message includes the line, column and character offset. In the requests library, response.json() raises the same kind of error when a response body is not JSON.

MessageCauseFix
Expecting value: line 1 column 1 (char 0)Empty string, HTML or other non-JSON text. Often an error page or an empty HTTP response.Print response.status_code and response.text before decoding.
Expecting property name enclosed in double quotesSingle-quoted keys, typically from str(dict) output, or a trailing comma on Python 3.12 and earlier.Produce the text with json.dumps instead of str(), or remove the trailing comma.
Illegal trailing comma before end of object / arrayA trailing comma, as reported by Python 3.13 and later.Remove the comma.
Expecting ',' delimiterA missing comma between items, or an unescaped quote inside a string.Add the comma or escape the quote.
Extra data: line 1 column NMore than one JSON value in the text, such as NDJSON.Decode line by line with json.loads per line.
Invalid control character at: line L column CA raw newline or tab inside a string.Escape it, or pass strict=False to accept control characters inside strings.
Unterminated string starting at: line L column CA string is missing its closing quote, often because the text was truncated.Close the string or fetch the complete payload.

Invisible errors: BOM, encoding and escapes

Some errors are hard to see because the bad character is invisible or looks fine.

Byte-order mark (BOM)

A file saved as "UTF-8 with BOM" starts with the bytes EF BB BF. RFC 8259 says JSON generators must not add one. Parsers may ignore it, but many treat it as an unexpected character at position 0, and you get a confusing error on a document that looks correct. Save the file as plain UTF-8 without a BOM, or strip those bytes before parsing.

Unescaped control and special characters

Inside a string, you must escape double quotes, backslashes and control characters such as literal newlines or tabs. A raw line break pasted into a string value is invalid. Write it as \n. Embedding one JSON document inside another string makes escaping tricky. See How to escape and unescape JSON strings.

Correctly escaped special characters inside a string value.json
{
  "path": "C:\\Users\\ada\\data.json",
  "quote": "She said \"hello\" today",
  "multiline": "line one\nline two"
}

Duplicate keys

RFC 8259 does not ban duplicate keys, but it says the result is unpredictable. Most parsers keep the last value without warning, so {"a": 1, "a": 2} becomes {"a": 2} and data is lost with no error. Some strict validators flag it. Treat duplicate keys as a bug even when nothing complains.

A fast workflow to find and fix JSON errors

In a large or minified document, you can't find a missing comma by eye. Use this loop instead:

  1. Paste the raw text into a validator to get the line and column of the first error.
  2. Reformat the document so nesting and commas sit on their own lines.
  3. Fix the character at (or just before) the reported position.
  4. Validate again. Parsers report one error at a time, so repeat until it passes.
JSON ValidatorValidate JSON and jump to the line and column of the error.→

Once the JSON parses, run it through a formatter. Structural mistakes, like a missing comma between two objects, become easy to see, and you get a clean, indented copy to commit.

JSON FormatterBeautify valid JSON to see its structure and confirm the fix.→

Frequently asked questions

Why does JSON.parse throw "SyntaxError: invalid JSON"?

JSON.parse throws a SyntaxError whenever its input is not valid JSON. Each engine words it differently. Firefox says "JSON.parse: unexpected character", Chrome says "Unexpected token" or "is not valid JSON", and Safari says "JSON Parse error". Common causes are trailing commas, single quotes, unquoted keys, an empty string, undefined, or an HTML page passed in place of JSON. Wrap the call in try/catch and log the raw text to see what you parsed.

Why does JSON not allow trailing commas?

RFC 8259 defines objects and arrays as comma-separated values, and every comma must be followed by another value. A trailing comma points to a value that isn't there, so strict parsers reject it. JavaScript and Python allow trailing commas in source code, which is where the habit comes from.

What does "Unexpected token < in JSON at position 0" mean?

The text starts with <, so it is almost certainly HTML, not JSON. This usually happens when an API returns an error page, a login redirect or a 404 instead of JSON. Log the raw response body before parsing to see what the server sent.

Are comments allowed in JSON?

No. Standard JSON has no comment syntax. A tool that accepts // or /* */ comments is parsing a superset such as JSONC or JSON5. Remove the comments before you pass the text to a strict parser, or switch the file to a format that supports them.

Why does my valid-looking JSON file fail to parse?

The usual invisible causes are a UTF-8 byte-order mark (BOM) at the start of the file, an unescaped control character inside a string, or extra content after the closing brace. Save the file as UTF-8 without a BOM and validate it to see the line and column of the error.

Does JSON allow duplicate keys?

The spec does not ban them, but it says the result is unpredictable. Most parsers keep the last value and drop the others without an error, so data can go missing. Treat duplicate keys as a mistake and remove them, even if your parser accepts the document.

What does "Unexpected end of JSON input" mean?

JSON.parse reached the end of the text before the value was complete. Most often the text is empty, for example a 204 No Content response or an unset variable. Check that the body is not empty before you parse it, and that the whole payload arrived.

What does "is not valid JSON" mean in Chrome?

It is the newer V8 wording for a JSON.parse failure in current Chrome, Edge and Node.js. The quoted text is what was passed in. "undefined" or "[object Object]" means a non-string was parsed, and "<!DOCTYPE "... means the response was HTML. Older versions reported the same problems as "Unexpected token X in JSON at position N".

How do I fix "Expecting value: line 1 column 1 (char 0)" in Python?

The text you decoded is empty or is not JSON. It is usually an empty HTTP response, an HTML error page or a file that was never written. Print the raw text and the HTTP status before calling json.loads or response.json(), and only decode when the response contains JSON.

How do I find which line has the JSON error?

Use a validator that reports line and column, or catch the parser exception. Python's json.JSONDecodeError has lineno, colno and pos. JavaScript reports a character position. The position marks where parsing failed, which is often one token after the real mistake.