When parsing JSON data in Python using json.loads() or json.load(), you might encounter the json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line X column Y (char Z). This specific error signals that the parser found something that looks like the start of an object key (property name), but it wasn't enclosed in the required double quotes ("), violating the strict JSON standard.
This guide explains the common causes of this error, primarily single-quoted keys/strings, and provides robust solutions using ast.literal_eval or by correcting the JSON format.
Understanding the Error: JSON String and Key Formatting Rules
JSON (JavaScript Object Notation) has a strict syntax, especially regarding strings and object keys (property names):
- Keys/Property Names: Must always be strings enclosed in double quotes (
"). - String Values: Must always be enclosed in double quotes (
"). Single quotes (') are not valid in standard JSON for keys or string values. - Other Values: Numbers, booleans (
true,false),null, arrays ([]), and nested objects ({}) follow their own formatting rules.
The error Expecting property name enclosed in double quotes occurs when the parser is inside a JSON object ({...}) and expects to find a key starting with " but encounters something else (often a single quote ' or an unquoted character).
Cause 1: Single Quotes Instead of Double Quotes
This is the most frequent cause. You might have a string that looks like a Python dictionary literal (which allows single quotes) but is not valid JSON.
import json
invalid_json_string = "{'name': 'Alice'}"
print(f"Input String: {invalid_json_string}")
try:
data = json.loads(invalid_json_string)
print(data)
except json.JSONDecodeError as e:
print(e)
invalid_json_string_2 = '{"name": \'Bob\'}' # Single quotes for value
try:
data = json.loads(invalid_json_string_2)
except json.JSONDecodeError as e:
print(f"Error with single-quoted value: {e}")Output:
Input String: {'name': 'Alice'}
Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
Error with single-quoted value: Expecting value: line 1 column 10 (char 9)Solution 1: Use ast.literal_eval() (for Python Dict Strings)
If your string represents a valid Python dictionary literal (which allows single quotes), but not necessarily valid JSON, the safest way to parse it is using ast.literal_eval.
import ast # Required import
python_dict_string = "{'name': 'Charlie', 'age': 25, 'active': True}"
print(f"Input String: {python_dict_string}")
try:
result_dict = ast.literal_eval(python_dict_string)
print(f"Parsed Dictionary: {result_dict}")
print(f"Type: {type(result_dict)}")
print(f"Accessing value: {result_dict['name']}")
except (ValueError, SyntaxError) as e:
print(f"ast.literal_eval error: Invalid Python literal - {e}")Output:
Input String: {'name': 'Charlie', 'age': 25, 'active': True}
Parsed Dictionary: {'name': 'Charlie', 'age': 25, 'active': True}
Type: <class 'dict'>
Accessing value: Charlieast.literal_evalsafely parses strings containing basic Python literals (dicts, lists, tuples, strings, numbers, booleans, None). It does not execute arbitrary code, making it much safer thaneval().- It correctly handles Python's
True,False,None.
Solution 2: Correct the Input to Valid JSON (Use Double Quotes)
The ideal solution is often to fix the source of the data so it produces valid JSON conforming to the standard (using double quotes).
import json
valid_json_string = '{"name": "David", "city": "Rome"}'
print(f"Valid Input String: {valid_json_string}")
try:
data = json.loads(valid_json_string)
print(f"Parsed Dictionary: {data}")
except json.JSONDecodeError as e:
print(f"Unexpected JSON Error: {e}") # Should not happen nowSolution 3: Use str.replace() (Use with Caution)
You can attempt to replace single quotes with double quotes before parsing. However, this is risky because legitimate single quotes within string values (like apostrophes) would also be incorrectly replaced.
import json
risky_string = "{'message': 'It's okay', 'status': 'pending'}"
potentially_fixed_string = risky_string.replace("'", '"')
print(f"String after replace: {potentially_fixed_string}")
try:
data = json.loads(potentially_fixed_string)
print(data)
except json.JSONDecodeError as e:
print(f"Error after replace: {e}") # Expecting ',' delimiter... or similar
simple_string = "{'key': 'value'}"
fixed_simple = simple_string.replace("'", '"') # Works for this specific simple case
data_simple = json.loads(fixed_simple)
print(f"Parsed simple fixed string: {data_simple}") # Output: Parsed simple fixed string: {'key': 'value'}Output:
String after replace: {"message": "It"s okay", "status": "pending"}
Error after replace: Expecting ',' delimiter: line 1 column 17 (char 16)
Parsed simple fixed string: {'key': 'value'}Cause 2: Missing Quotes Entirely (Less Common for this specific error)
While less common for the exact error message Expecting property name enclosed in double quotes, forgetting quotes around a key entirely would also cause a parse error, potentially a similar one if the unquoted key starts with a character invalid at that position.
invalid_json = '{"name": "Eve", age: 25}'
json.loads(invalid_json) # ⛔️ JSONDecodeError: Expecting property name enclosed in double quotes...Solution: Ensure all keys are strings enclosed in double quotes.
Related Issue: Trailing Commas
Trailing commas (a comma after the last key-value pair in an object or the last element in an array) are not allowed in standard JSON, although they are allowed in Python literals. They cause a different JSONDecodeError (usually Expecting property name enclosed in double quotes or Expecting value).
invalid_json_trailing = '{"name": "Anna", "age": 23,}'
try:
data = json.loads(invalid_json_trailing)
except json.JSONDecodeError as e:
print(f"Error with trailing comma: {e}")Handling Trailing Commas with ast.literal_eval
Since Python literals do allow trailing commas, ast.literal_eval can often parse strings containing them (provided the rest is valid Python literal syntax).
import ast
python_literal_trailing = "{'name': 'Grace', 'id': 10,}" # Trailing comma okay for Python dict
try:
data = ast.literal_eval(python_literal_trailing)
print(f"Parsed with trailing comma (ast): {data}") # {'name': 'Grace', 'id': 10}
except Exception as e:
print(e)Output:
Parsed with trailing comma (ast): {'name': 'Grace', 'id': 10}Handling Trailing Commas with PyYAML (Optional)
YAML is generally more lenient than JSON and often handles trailing commas. Requires pip install pyyaml.
import yaml
yaml_string_trailing = '{"name": "Heidi", "value": true,}'
try:
data = yaml.safe_load(yaml_string_trailing)
print(f"Parsed with trailing comma (yaml): {data}") # {'name': 'Heidi', 'value': True}
except Exception as e:
print(e)Output:
Parsed with trailing comma (yaml): {'name': 'Heidi', 'value': True}Handling Trailing Commas with str.replace()
You can try to remove trailing commas before braces/brackets, but this is complex and potentially error-prone.
import json
invalid_json_trailing = '{"name": "Ivan", "items": [1, 2,],}'
cleaned = invalid_json_trailing.replace(',}', '}').replace(',]', ']')
print(f"Cleaned trailing commas: {cleaned}") # {"name": "Ivan", "items": [1, 2]}
try:
data = json.loads(cleaned)
print(f"Parsed cleaned trailing commas: {data}") # {'name': 'Ivan', 'items': [1, 2]}
except json.JSONDecodeError as e:
print(e)Output:
Cleaned trailing commas: {"name": "Ivan", "items": [1, 2]}
Parsed cleaned trailing commas: {'name': 'Ivan', 'items': [1, 2]}Validating JSON
Use online JSON validators or libraries like jsonschema to verify if a string conforms to the JSON standard before attempting to parse it with json.loads().
json.loads() vs. json.dumps()
json.loads(json_string): Loads a JSON formatted string into a Python object (dict, list, etc.).json.dumps(python_object): Dumps a Python object into a JSON formatted string.
Ensure you are using the correct function for your goal. Trying to json.loads() an actual Python dictionary will fail.
Conclusion
The JSONDecodeError: Expecting property name enclosed in double quotes specifically points to invalid JSON syntax where an object key (property name) is not correctly enclosed in double quotes ("), often because single quotes (') were used instead.
Key Solutions:
- If the input string represents a Python dictionary literal (allowing single quotes), use
ast.literal_eval()for safe parsing. - If the input should be valid JSON, ensure the source generates it correctly using double quotes (
") for all keys and string values. - Using
str.replace("'", '"')is risky and generally discouraged unless the input format is extremely simple and controlled. - Remember that trailing commas also invalidate standard JSON and should be handled appropriately (often
ast.literal_evalworks if the rest is Python-like).
Verifying input data format and using the appropriate parsing tool (json.loads for strict JSON, ast.literal_eval for Python literals) are crucial for avoiding this error.