A JSON syntax error means a parser reached a character it cannot reconcile with the JSON grammar and gave up. The frustrating part is that the message often points at where parsing *failed*, not where you made the mistake, so a missing comma on line 12 can surface as an error on line 14.
JSON is defined by RFC 8259, and the standard is deliberately strict: no trailing commas, no comments, double-quoted keys and strings only. Most errors come from writing JSON as if it were JavaScript or Python source. This guide catalogues the errors you will actually hit, shows the fix for each, and explains how to decode the line and column numbers your parser reports.
What Counts as a JSON Syntax Error
JSON has a small, rigid grammar. A document is a single value: an object, an array, a string, a number, true, false, or null. Objects are comma-separated "key": value pairs inside braces; arrays are comma-separated values inside brackets. Anything outside that grammar is a syntax error, even if it looks reasonable to a human.
The strictness is the whole point. Because RFC 8259 forbids ambiguity, a valid JSON document parses identically in every conforming library. That is why the format is trustworthy for APIs and config files, and also why the parser refuses to 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/Infinityin 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. JavaScript's JSON.parse gives a zero-based character offset and, depending on the engine, a message like "Unexpected token } in JSON at position 27" (older V8, Safari, Firefox) or the newer, more descriptive "Expected double-quoted property name in JSON at position 27" (recent V8). Python's json module gives you line, column, and character offset directly. Whatever the wording, the number marks where the parser *stopped*, which is usually the first character it could not accept.
The mistake is frequently just before that point. A missing comma is only detected when the parser hits the next key, so the reported column lands on that next key, not on the gap where the comma belongs. Read one token backward from the position the error names.
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})")
# Expecting property name enclosed in double quotes at line 1 column 27 (char 26)Here the trailing comma after 36 sits at column 26, and the parser reports column 27 because it expected another key and found } instead. The engine is telling you "I wanted a property name here," which is your cue that the comma before it is spurious.
The Most Common JSON Syntax Errors and Their Fixes
The overwhelming majority of JSON syntax errors fall into a handful of categories, almost all caused by treating JSON like JavaScript or Python. Here is the quick-reference table, followed by the fixes that need more than one line.
| Mistake | Invalid | Valid |
|---|---|---|
| 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
The single most common error. JavaScript, Python, and most editors happily accept a comma after the last element; JSON does not. Deleting one is easy, but they hide inside deeply nested structures, which is where a reformat helps you spot them.
Single quotes and unquoted keys
JSON recognizes only double quotes, for both keys and string values. Objects copied from JavaScript source or a Python dict repr will use single quotes or bare identifiers and must be converted. Note that Python's str(dict) also renders True, False, and None, which are not valid JSON; use json.dumps instead, covered in Working with JSON in Python.
Comments
There is no comment syntax in JSON. If a config parser accepted // comments, it was parsing JSONC, not JSON. Strip comments before feeding the text to a strict parser.
{
"id": 1,
"name": "Ada Lovelace",
"active": true,
"roles": ["admin", "editor"],
"score": 7,
"manager": null
}Decoding "Unexpected Token" and "Unexpected End of Input"
These two messages account for most JavaScript-side parse failures, and they mean opposite things. Recent V8 versions rephrase them (for example, "Expected ',' or '}' after property value"), but the underlying distinction is the same.
Unexpected token
The parser found a character that cannot legally appear where it is. Common causes: a stray comma, a single quote, an unquoted word like undefined, or accidentally parsing an HTML error page (which starts with <) that your server returned instead of JSON. A message like "Unexpected token < in JSON at position 0" almost always means the response was HTML, not JSON, so inspect the raw response before blaming the parser.
Unexpected end of input
The parser reached the end of the string while still waiting for something to close: an open brace, bracket, or quote. The document was truncated or a closing character is missing. This also appears when you call JSON.parse("") on an empty body, which throws "Unexpected end of JSON input."
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 } }Invisible Errors: BOM, Encoding, and Escapes
Some errors survive a visual scan because the offending character is invisible or looks fine.
Byte-order mark (BOM)
A file saved as "UTF-8 with BOM" begins with the bytes EF BB BF. RFC 8259 forbids a JSON generator from adding one, and while a parser may choose to ignore it, many treat it as an unexpected character at position 0, producing a baffling error on a document that looks perfect. Re-save the file as plain UTF-8 without a BOM, or strip the leading bytes before parsing.
Unescaped control and special characters
Inside a string, double quotes, backslashes, and control characters like literal newlines or tabs must be escaped. A raw line break pasted into a string value is invalid; it must be written as \n. If you are embedding one JSON document inside another string, escaping gets fiddly fast, so see How to Escape and Unescape JSON Strings.
{
"path": "C:\\Users\\ada\\data.json",
"quote": "She said \"hello\" today",
"multiline": "line one\nline two"
}Duplicate keys
RFC 8259 does not forbid duplicate keys outright, but it declares the result unpredictable. In practice most parsers keep the last value silently, so {"a": 1, "a": 2} becomes {"a": 2} with no error, quietly dropping data. Some strict validators flag it. Treat duplicate keys as a bug even when nothing complains.
A Fast Workflow for Locating and Fixing Faults
When a document is large or minified, hunting for a comma by eye is hopeless. A reliable loop is: validate to get the exact line and column, reformat to expose the structure, fix the reported spot, and revalidate.
- Paste the raw text into a validator to get the precise line and column of the first fault.
- Reformat the document so nesting and commas are visible on their own lines.
- Fix the character at (or just before) the reported position.
- Revalidate; parsers report one error at a time, so repeat until it is clean.
Once it parses, running it through a formatter makes structural mistakes like a missing comma between two objects obvious, and gives you a clean, indented copy to commit.
{ }JSON FormatterBeautify valid JSON to reveal structure and confirm the fix.→