pandas-dev/pandas · error · ValueError
Invalid Attribute context {type(ctx).__name__}
Error message
Invalid Attribute context {type(ctx).__name__} What it means
visit_Attribute (expr.py:643) only handles ast.Load context — i.e. reading an attribute like df.col. Any other context (ast.Store for assignment targets, ast.Del for deletion) is meaningless inside an eval expression and falls through to raise ValueError naming the context class. In practice the visit_Assign check for ast.Name usually catches attribute-LHS first, so this fires for unusual attribute-in-store-context AST shapes.
Source
Thrown at pandas/core/computation/expr.py:665
ctx = node.ctx
if isinstance(ctx, ast.Load):
# resolve the value
visited_value = self.visit(value)
if hasattr(visited_value, "value"):
resolved = visited_value.value
else:
resolved = visited_value(self.env)
try:
v = getattr(resolved, attr)
name = self.env.add_tmp(v)
return self.term_type(name, self.env)
except AttributeError:
# something like datetime.datetime where scope is overridden
if isinstance(value, ast.Name) and value.id == attr:
return resolved
raise
raise ValueError(f"Invalid Attribute context {type(ctx).__name__}")
def visit_Call(self, node, side=None, **kwargs):
if isinstance(node.func, ast.Attribute) and node.func.attr != "__call__":
res = self.visit_Attribute(node.func)
elif not isinstance(node.func, ast.Name):
raise TypeError("Only named functions are supported")
else:
try:
res = self.visit(node.func)
except UndefinedVariableError:
# Check if this is a supported function name
try:
res = FuncNode(node.func.id)
except ValueError:
# Raise original error
raise
if res is None:View on GitHub (pinned to 71959b8cb9)
Solutions
- Rewrite so attributes are only read, never assigned/deleted inside eval.
- Do attribute assignment in plain Python outside the eval string.
- If building AST programmatically, ensure Attribute nodes use ast.Load.
Example fix
// before
# attribute in a store context (rare, usually hand-built AST)
// after
# assign to a plain name and set the attribute in Python:
df.eval('tmp = a + b')
df.obj.tmp = df['tmp'] Defensive patterns
Strategy: validation
Validate before calling
import ast
def validate_attribute_load_only(expr: str) -> None:
for node in ast.walk(ast.parse(expr, mode='eval')):
if isinstance(node, ast.Attribute) and not isinstance(node.ctx, ast.Load):
raise ValueError(
f'attribute in {type(node.ctx).__name__} context not supported'
)
validate_attribute_load_only(expr) Type guard
import ast
def attributes_are_load_only(expr: str) -> bool:
return all(
isinstance(n.ctx, ast.Load)
for n in ast.walk(ast.parse(expr, mode='eval'))
if isinstance(n, ast.Attribute)
) Try / catch
try:
df.eval(expr)
except ValueError as e:
if 'Invalid Attribute context' in str(e):
# move attribute assignment out of eval into Python
setattr(obj, attr, value)
raise Prevention
- Use attributes only for reads inside eval expressions.
- Do attribute writes via the object API in plain Python.
- If constructing AST, set Attribute.ctx to ast.Load.
When it happens
Trigger: An attribute access appearing in a Store or Del AST context inside the expression tree — typically from hand-built AST or from preprocessing that produces non-Load attribute nodes.
Common situations: Internal tooling that constructs AST nodes directly. Parsers/preparsers that change node contexts. Very rarely reachable from user strings because earlier checks reject attribute assignment.
Related errors
- The '@' prefix is only supported by the pandas parser
- The '@' prefix is not allowed in top-level eval calls. pleas
- expr must be a string to be evaluated, {type(expr)} given
- multi-line expressions are only valid in the context of data
- Multi-line expressions are only valid if all expressions con
AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07).
Data as JSON: /api/errors/f2bb8fcae06d8e74.
Report an issue: GitHub.