How to fix a JSON syntax error

What the message means in each language, the eight mistakes behind nearly all of them, and how to get from a character offset to the thing you actually typed wrong.

Free toolJSON Formatter & ValidatorPretty-print, minify, validate and explore a JSON payload as a collapsible tree. Errors are pinned to a line and a column.Open the formatter

The short answer

Read the position in the error, then look at the character just before it. A parser reports where it gave up, not where the mistake is, and the mistake is almost always one token earlier. A missing comma is reported at the start of the next property, and an unclosed string is reported at the end of the file.

Eight mistakes account for nearly every JSON error anyone hits: a trailing comma, a missing comma, single quotes, unquoted keys, comments, curly quotes from a word processor, an unescaped backslash or quote inside a string, and a capitalised True or None pasted out of Python.

What your language is telling you

The messages differ enormously in quality. Python names the problem and gives a line and a column; JavaScript gives a character offset and, in older browsers, a message that describes the symptom rather than the cause.

MessageWhere fromWhat it usually is
Unexpected token } in JSON at position 42JavaScriptA trailing comma before that brace.
Expected double-quoted property name in JSONJavaScript, V8 since 2023An unquoted key, or a trailing comma.
Unexpected token < in JSON at position 0JavaScriptNot JSON at all. An HTML error page.
Unexpected end of JSON inputJavaScriptEmpty body, or a truncated download.
Expecting ',' delimiter: line 3 column 5PythonA missing comma between two properties.
Expecting property name enclosed in double quotesPythonAn unquoted or single-quoted key, or a trailing comma.
Extra data: line 2 column 1PythonTwo documents in one file. Usually NDJSON.
Syntax errorPHPAll of the above. PHP does not say which.
Unexpected character ('}' (code 125))Java, JacksonA trailing comma, with the position given.

PHP is the worst of these by some distance. json_decode returns null and sets an error you have to ask for, so call json_last_error_msg(), or pass JSON_THROW_ON_ERROR and let it throw.

The eight mistakes

1. A trailing comma

Valid in JavaScript, invalid in JSON, and identical on screen. It is reported at the closing brace or bracket rather than at the comma itself.

{ "a": 1, "b": 2, }        // the comma after 2 is the error

2. A missing comma

Reported at the start of the next property, which is why the line number in the error often looks one too high. Check the end of the line above the one named.

3. Single quotes

JSON has exactly one string delimiter and it is the double quote. Single quotes are a JavaScript and Python habit, and no JSON parser accepts them.

4. Unquoted property names

{ name: "Ada" } is a JavaScript object literal, not JSON. Every key needs its own double quotes.

5. Comments

Neither style is allowed. If the file is a VS Code settings file, a tsconfig or an ESLint config, it is JSONC rather than JSON, and any general parser will reject it.

6. Curly quotes

The signature of JSON that has been through Word, Google Docs, Slack or Notes. Autocorrect replaces the straight quote with a typographic one, which is a different character, and the error reads as an unexpected token where a string should be.

7. An unescaped backslash or quote inside a string

Windows paths are the usual source. "C:\Users\ada" is invalid, because \U is not an escape. Write "C:\\Users\\ada". The same applies to a quote inside a quoted string, which has to be written as \".

8. Python and PHP literals

True, False and None are Python. JSON writes true, false and null, all lower case. This is what you get from pasting the output of a print() rather than of json.dumps(). NaN and Infinity have no JSON representation at all.

Turning a character offset into a place in the file

JavaScript reports a position, not a line, which is useless on a minified payload. Both of these turn one into the other.

// Node: print the 80 characters around position 4812
const text = require('fs').readFileSync('data.json', 'utf8');
console.log(text.slice(4762, 4862));
# Python: the message already carries line and column
python -m json.tool data.json

Or paste the file into the JSON formatter, which reports the line and the column, shows the characters either side of the fault with a mark under it, and jumps the cursor there.

Checking JSON from the command line

Four one-liners, in rough order of how likely the tool is to already be installed.

python -m json.tool data.json          # validates and pretty-prints
jq . data.json                        # same, with better errors
node -e "JSON.parse(require('fs').readFileSync(0,'utf8'))" < data.json
npx jsonlint -q data.json             # line and column, no install

In VS Code, set the language mode to JSON and the problems panel lists every error with a line number, then Format Document tidies it. Set the mode to "JSON with Comments" for a tsconfig or a settings file, or every comment will be underlined as an error.

When the JSON is not the problem

  • You were sent HTML. An error page, a login redirect or a captive portal. Print the first 200 characters of the body before parsing it.
  • The response was truncated. A timeout or a dropped connection leaves valid JSON that simply stops. The error is at the very end of the file.
  • There is a byte order mark. Saving as UTF-8 in Notepad or Excel puts three invisible bytes at the start. Some parsers cope and some report an unexpected character at position 0. Save as "UTF-8 without BOM".
  • It is double-encoded. If the whole document is one string full of \", it has been serialised twice. Parse it twice, and fix the producer.
  • It is NDJSON. One object per line, no commas and no wrapping array. Read it line by line.

Not hitting it again

Hand-written JSON is where nearly all of this comes from. Build the value in your language and let the serialiser write it: json.dumps, JSON.stringify or json_encode. None of them can produce a trailing comma or an unquoted key.

For configuration a human has to edit, use a format that expects a human: YAML, TOML, or JSONC if the tool reading it supports comments. And send large integers such as IDs as strings, because JSON has no size limit on a number and the language reading it does.

Frequently asked questions

Can a JSON file have comments?

No. Douglas Crockford removed them from the format deliberately, because people were using them to carry parsing directives. Every parser that appears to accept them is reading JSONC or JSON5 instead, which are different formats that happen to look the same. VS Code settings files are JSONC, which is why the comments in them work there and break everywhere else.

Are trailing commas ever allowed?

Not in JSON, no, and this is the single most common error there is. JavaScript has allowed them in object and array literals since ES5, so code that looks identical works in one place and fails in the other. If you are writing JSON by hand and keep hitting this, write it as a value in your language and serialise it instead.

Why is my JSON full of backslashes before every quote?

Because it has been encoded twice. Something serialised an object to a JSON string, then serialised that string again, so the inner document arrived as one long value rather than as an object. Parse it, then parse the result. The real fix is upstream: whatever built the payload is calling its serialiser on text that was already JSON.

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

That you got HTML back, not JSON, and the first character of it is the opening bracket of <!DOCTYPE html>. It is nearly always a 404, a 500, a login redirect or a proxy error page being handed to a JSON parser. Log the raw response body before parsing it and the cause is usually visible in the first line.

Can one file hold several JSON objects?

Not as a single JSON document, which holds exactly one value. A file with one object per line is NDJSON, also called JSON Lines, and it is read a line at a time rather than in one parse. If you are getting "Extra data" from Python or "Unexpected non-whitespace character" from JavaScript, this is usually why.

Is a top-level array valid JSON?

Yes. So is a bare string, number, true, false or null. The original specification required an object or an array at the top, and RFC 7159 dropped that in 2014, so any parser written since accepts them. A few very old libraries still refuse, which is worth knowing before blaming your data.

Does the order of keys in a JSON object matter?

Not to the format. An object is defined as an unordered set of name and value pairs, so two documents with the same pairs in a different order carry the same data. In practice most parsers preserve the order they read, and Python 3.7 dictionaries keep insertion order, so code that depends on it usually works and is still a bug waiting for a different parser.

move openesc close