Skip to main content

How to Resolve Python Error "JSONDecodeError: Expecting property name enclosed in double quotes"

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: Uses single quotes for the key 'name' and its value
invalid_json_string = "{'name': 'Alice'}"

print(f"Input String: {invalid_json_string}")

try:
# ⛔️ json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
# The parser sees '{' then expects '"' but finds "'" at index 1 (char 1).
data = json.loads(invalid_json_string)
print(data)
except json.JSONDecodeError as e:
print(e)

# Another example
invalid_json_string_2 = '{"name": \'Bob\'}' # Single quotes for value
try:
# ⛔️ json.decoder.JSONDecodeError: Expecting 'STRING' or '}' delimiter: line 1 column 10 (char 9)
# Error message might vary slightly depending on where the single quote is,
# but the root cause is invalid quoting.
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}")
# Output: Input String: {'name': 'Charlie', 'age': 25, 'active': True}

try:
# ✅ Safely evaluate the Python literal string
result_dict = ast.literal_eval(python_dict_string)

print(f"Parsed Dictionary: {result_dict}")
# Output: Parsed Dictionary: {'name': 'Charlie', 'age': 25, 'active': True}

print(f"Type: {type(result_dict)}")
# Output: Type: <class 'dict'>

print(f"Accessing value: {result_dict['name']}")
# Output: Accessing value: Charlie

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: Charlie
  • ast.literal_eval safely parses strings containing basic Python literals (dicts, lists, tuples, strings, numbers, booleans, None). It does not execute arbitrary code, making it much safer than eval().
  • 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 (double quotes for keys and strings)
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}")
# Output: Parsed Dictionary: {'name': 'David', 'city': 'Rome'}
except json.JSONDecodeError as e:
print(f"Unexpected JSON Error: {e}") # Should not happen now
note

Ensure all systems generating the JSON output adhere to the double-quote requirement.

Solution 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 input - single quotes for keys, but also an apostrophe inside value
risky_string = "{'message': 'It's okay', 'status': 'pending'}"

# Attempt replacement (potentially problematic)
potentially_fixed_string = risky_string.replace("'", '"')
print(f"String after replace: {potentially_fixed_string}")
# Output: String after replace: {"message": "It"s okay", "status": "pending"}
# Note: This created invalid JSON because of the double quote inside "It"s okay"

try:
# ⛔️ This will likely fail with a different JSONDecodeError now
data = json.loads(potentially_fixed_string)
print(data)
except json.JSONDecodeError as e:
print(f"Error after replace: {e}") # Expecting ',' delimiter... or similar

# Only use replace() if you are ABSOLUTELY sure single quotes are ONLY used as delimiters
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'}
note

Recommendation: Avoid str.replace() for fixing quotes unless the input structure is extremely simple and controlled. Prefer ast.literal_eval or fixing the source JSON generation.

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: age key is not quoted at all
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.

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 comma after 23
invalid_json_trailing = '{"name": "Anna", "age": 23,}'
try:
# ⛔️ json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes...
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,],}'

# Basic removal (might break strings containing ',}' or ',]')
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:

  1. If the input string represents a Python dictionary literal (allowing single quotes), use ast.literal_eval() for safe parsing.
  2. If the input should be valid JSON, ensure the source generates it correctly using double quotes (") for all keys and string values.
  3. Using str.replace("'", '"') is risky and generally discouraged unless the input format is extremely simple and controlled.
  4. Remember that trailing commas also invalidate standard JSON and should be handled appropriately (often ast.literal_eval works 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.