Skip to content

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

Fix the JSONDecodeError in Python when keys use single quotes by converting to valid JSON with double quotes or using ast.literal_eval for Python dictionary strings.

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: 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 = '{"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 now

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_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.

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:

  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.

Navigation