Expecting Property Name Enclosed in Double Quotes — Three Causes, Not One
The message names one problem, but Python raises it for at least three different mistakes. Rather than assuming quotes are the issue, read the character at the reported position — that is what tells you which one you actually have.
The short answer
Python raises Expecting property name enclosed in double quotes when it reaches a point where a property name should begin and finds something that is not one. That happens for 3 different mistakes, and the message is identical for all of them: a single-quoted key, a key with no quotes at all, and a trailing comma before the closing brace.
So the wording is misleading in a specific way — it sounds like a quoting problem, and a third of the time it is not one. The useful move is to look at the character sitting at the position Python reports. An apostrophe means single quotes, a bare letter means an unquoted key, and a closing brace means a stray comma.
Why one message covers several problems
Python's parser is not describing your mistake. It is describing its own state: it was ready to read a property name and the next characters were not a valid one. Every route into that state produces the same sentence, because the sentence is about the parser, not about the document.
Measured on Python 3.9.6, all three inputs below raise the identical message and differ only in the reported position:
| What you typed | Cause | Reported at |
|---|---|---|
| {'name': "John"} | Single-quoted property name | line 1 column 2 (char 1) |
| {name: "John"} | Unquoted property name | line 1 column 2 (char 1) |
| {"a": 1,} | Trailing comma before the closing brace | line 1 column 9 (char 8) |
Single-quoted property names
The most common cause, and the one the message implies. JSON allows only double quotes around property names — single quotes are not an alternative form, they are simply not part of the grammar.
{'name': "John"} // not JSON
{"name": "John"} // JSONThe reported position is the opening apostrophe. If the value is single-quoted as well, fixing only the key moves you to a different error rather than to success — see the related messages at the end.
Property names with no quotes
JSON requires quotes around every property name, even a plain one with no spaces or reserved characters. This usually arrives from JavaScript, where object literals do not need them:
{name: "John"} // valid JavaScript object literal, not JSON
{"name": "John"} // JSONPython reports this at exactly the same position as the single-quote case, which is why the message alone cannot separate them.
A trailing comma before the closing brace
This is the cause people miss, because nothing in the message suggests punctuation and the reported position points at the brace rather than the comma.
{"a": 1,} // trailing comma — not allowed in JSON
{"a": 1} // JSONThe parser consumed the comma, correctly expected another property to follow, and found the end of the object instead — so from its point of view a property name really was missing. JSON has no trailing-comma allowance, unlike JavaScript, Python literals, and config formats such as JSONC. Trailing commas across objects and arrays covers both containers and what each engine reports; a trailing comma in an array produces a different message, noted below.
A Python dict is not JSON
A large share of these errors come from one habit: printing a dictionary and trying to parse the result. {'name': 'John'} is valid Python and invalid JSON, and the difference is not cosmetic — they are different formats that happen to look similar.
# Valid Python. Not valid JSON.
data = {'name': 'John'}
# What json.dumps produces from it — note the quotes change:
json.dumps(data) -> {"name": "John"}
# Parsing the repr of a dict is the usual way people end up here:
json.loads(str(data))
# JSONDecodeError: Expecting property name enclosed in double quotesIf the text came from a dict, the fix is to serialise it properly with json.dumps at the source rather than to patch quotes at the destination. If it arrived as text you cannot change and it is genuinely a Python literal rather than JSON, ast.literal_eval parses it as Python — but that is a different operation from parsing JSON, and worth being deliberate about.
Worth stating plainly: the document being invalid JSON does not mean it is invalid. It may be perfectly good Python or JavaScript. What failed is the attempt to read it as JSON.
What other parsers say about the same input
V8 — the engine behind Node.js and browser JavaScript — separates the cases Python merges. That makes a second opinion genuinely useful for the trailing-comma case in particular:
| Input | Python 3.9.6 | V8 13.6 |
|---|---|---|
| {'name': "John"} | Expecting property name enclosed in double quotes | Expected property name or '}' in JSON at position 1 |
| {name: "John"} | Expecting property name enclosed in double quotes | Expected property name or '}' in JSON at position 1 |
| {"a": 1,} | Expecting property name enclosed in double quotes | Expected double-quoted property name in JSON at position 8 |
Note the third row: V8 says Expected double-quoted property name where Python gives its generic sentence, and the two engines report the quoting cases with wording that points at the brace rather than the quotes. Neither is authoritative about your document — they are two implementations of the same grammar describing the same failure differently. These strings are from the versions listed at the end and other releases word them differently.
Finding the actual mistake
Python hands you the offset; printing the text around it turns a generic message into a specific one:
try:
json.loads(text)
except json.JSONDecodeError as e:
# e.pos is the character offset the parser stopped at
print(e.msg, "at", e.pos)
print(repr(text[max(0, e.pos - 20):e.pos + 20]))- 1. Read the position, not just the messagePython reports a line, column, and character offset. The character sitting at that offset is what distinguishes the three causes — an apostrophe, a bare letter, or a closing brace.
- 2. An apostrophe means a single-quoted keyReplace the surrounding single quotes with double quotes. If the value is single-quoted too, that produces a different message — Expecting value — so fix both.
- 3. A letter or digit means the key was never quotedJSON requires quotes around property names even when the name has no spaces or reserved characters. JavaScript object literals do not, which is where the habit usually comes from.
- 4. A closing brace means a trailing commaThe parser consumed a comma, expected another property, and found the end of the object instead. Delete the comma before the brace. This one is easy to miss because the reported position is the brace, not the comma.
- 5. Check whether you are parsing JSON at allIf the text came from str() on a dict, or from a config file that allows comments, the fix is not to patch the quotes but to serialise or parse it with the right tool.
Checking the corrected document
Once the syntax is fixed, {"name": "John"}parses everywhere. To confirm a correction — or to get V8's reading of a document Python only described vaguely — paste it into the JSON Formatter. It reports V8's parser message with a position and line and column, and formats the document once the syntax is valid.
It does not repair anything. It will not convert single quotes, strip a trailing comma, or turn a Python dict into JSON — invalid input produces the error and no output. Treat it as a second parser opinion alongside Python rather than a replacement for it, and remember that the authority on whether your Python code works is Python. Parsing runs in your browser, so a payload containing real data is not uploaded anywhere.
Related messages you may see instead
Two near neighbours produce different wording, so a search for the property-name message will not lead you to them:
| Input | Python | V8 |
|---|---|---|
| {"name": 'John'}Single-quoted value rather than key | Expecting value (line 1 column 10) | Unexpected token ''', "{"name": 'John'}" is not valid JSON |
| [1, 2,]Trailing comma in an array rather than an object | Expecting value (line 1 column 7) | Unexpected token ']', "[1, 2,]" is not valid JSON |
A different situation entirely is an error mentioning < or <!DOCTYPE. That means no JSON arrived at all and the response was an HTML page — a different problem with a fix upstream of the document.
Versions measured
Error wording is an implementation detail and changes between releases. The strings on this page were produced by:
- Python (stdlib json) —
3.9.6 - V8 / Node.js —
13.6 / 24.16.0 - DataToolsHQ JSON Formatter —
native JSON.parse (V8)
The grammar underneath does not change: property names take double quotes and trailing commas are not allowed, in every version.