Skip to content

How to Resolve "ValueError: malformed node or string" with ast.literal_eval() in Python

Fix the ValueError when using ast.literal_eval() by ensuring input is a valid Python literal string, checking types, and using json.loads() for JSON data instead.

The ValueError: malformed node or string error arises when you use the ast.literal_eval() function in Python to parse a string that doesn't represent a valid Python literal.

This guide explains the common causes of this error, provides robust solutions, and distinguishes ast.literal_eval() from json.loads().

Understanding the Error

The ast.literal_eval() function is designed to safely evaluate a string containing a Python literal (like a list, dictionary, number, string, boolean, or None). It's not a general-purpose Python code interpreter (that would be eval(), which is dangerous).

The error occurs in these main cases:

  • Incorrect Data Type: You pass a value that isn't a string to ast.literal_eval().
  • Invalid Syntax: The string doesn't represent a valid Python literal.
  • JSON Data: You are trying to use ast.literal_eval() to parse a JSON string (use json.loads() instead).

Example of the error:

import ast

a_dict = {
    'first': 'tom',
    'last': 'nolan',
}

try:
  print(ast.literal_eval(a_dict))
except ValueError as e:
    print(e)
  • The ast.literal_eval() method expects a string as an argument, not a dictionary.

Solutions

Passing Valid Python Literals

Ensure the string you pass to ast.literal_eval() represents a valid Python literal:

import ast

a_str = '''{
    "first": "tom",
    "last": "nolan"
}''' # Notice that this is now a string representing a dictionary.

result = ast.literal_eval(a_str) # This will work correctly
print(result)
print(type(result))  # Output: <class 'dict'>

Checking for String Type Before Evaluation

If you're uncertain about the input type, check if it's a string before calling ast.literal_eval():

import ast

a_dict = {
    'first': 'tom',
    'last': 'nolan',
}

if isinstance(a_dict, str):
    result = ast.literal_eval(a_dict)
else:
    result = a_dict

print(result)         # Output: {'first': 'tom', 'last': 'nolan'}
print(type(result))   # Output: <class 'dict'>
  • If the type of the value is string, then call ast.literal_eval() on it, otherwise return the original value.

Using json.loads() for JSON Strings (Important Distinction)

ast.literal_eval() is not for parsing JSON. If you have a JSON string, use json.loads() instead:

import json

a_str = '''{
    "first": "tom",
    "last": "nolan",
    "is_programmer": true,
    "salary": null
}'''

result = json.loads(a_str)  # Use json.loads for JSON

print(result)        # Output: {'first': 'tom', 'last': 'nolan', 'is_programmer': True, 'salary': None}
print(type(result))  # Output: <class 'dict'>
  • The json.loads() parses a JSON string and returns a python object, a dictionary in this case.

Conclusion

The ValueError: malformed node or string error with ast.literal_eval() indicates that the input isn't a valid Python literal string.

Always check the input type, ensure the string represents a valid literal, and use json.loads() for JSON data.

By understanding the intended use of ast.literal_eval(), you can avoid this error and safely evaluate string representations of Python literals.

Navigation