pandas-dev/pandas · error · SyntaxError
left hand side of an assignment must be a single resolvable
Error message
left hand side of an assignment must be a single resolvable name
What it means
After visiting the assignment target, expr.py:635 does self.assigner = getattr(assigner, 'name', assigner). If that resolves to None (the visited term has name=None, or the Name visit returned something without a usable name), the assignment LHS is not a resolvable identifier and pandas raises SyntaxError. This is a defensive guard for malformed-but-parsed LHS nodes.
Source
Thrown at pandas/core/computation/expr.py:637
set the assigner at the top level, must be a Name node which
might or might not exist in the resolvers
"""
if len(node.targets) != 1:
raise SyntaxError("can only assign a single expression")
if not isinstance(node.targets[0], ast.Name):
raise SyntaxError("left hand side of an assignment must be a single name")
if self.env.target is None:
raise ValueError("cannot assign without a target object")
try:
assigner = self.visit(node.targets[0], **kwargs)
except UndefinedVariableError:
assigner = node.targets[0].id
self.assigner = getattr(assigner, "name", assigner)
if self.assigner is None:
raise SyntaxError(
"left hand side of an assignment must be a single resolvable name"
)
return self.visit(node.value, **kwargs)
def visit_Attribute(self, node, **kwargs):
attr = node.attr
value = node.value
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:View on GitHub (pinned to 71959b8cb9)
Solutions
- Ensure the LHS is a plain, non-empty identifier string.
- Validate the generated name is a str and not None before building the expression.
- Avoid constructing expressions from untrusted/dynamic LHS tokens.
Example fix
// before
name = None
df.eval(f'{name} = a + b')
// after
name = 'c'
df.eval(f'{name} = a + b') Defensive patterns
Strategy: validation
Validate before calling
import ast
import keyword
def validate_lhs_resolvable(expr: str) -> None:
for stmt in ast.parse(expr, mode='exec').body:
if isinstance(stmt, ast.Assign):
name = stmt.targets[0].id
if not name or keyword.iskeyword(name):
raise SyntaxError(f'LHS name {name!r} is not a valid resolvable identifier')
validate_lhs_resolvable(expr) Type guard
import ast, keyword
def lhs_is_valid_identifier(expr: str) -> bool:
for s in ast.parse(expr, mode='exec').body:
if isinstance(s, ast.Assign):
n = s.targets[0].id
if not n or keyword.iskeyword(n):
return False
return True Try / catch
try:
df.eval(expr)
except SyntaxError as e:
if 'resolvable name' in str(e):
# choose a concrete column name and rebuild
df.eval('new_col = a + b')
raise Prevention
- Always assign to a concrete, non-keyword column name.
- When templating LHS from data, validate the name is a non-empty identifier.
- Avoid Python keywords as column names in eval assignments.
When it happens
Trigger: Edge cases where a syntactically-valid LHS visits to a term whose .name attribute is None — e.g. a constant or a Term constructed without a name. Rare in normal use; usually surfaces from dynamically generated expression strings.
Common situations: Programmatically building LHS names from data that yields empty/None. Bugs in custom resolvers that return misshapen Term objects. Internal callers constructing AST by hand.
Related errors
- multi-line expressions are only valid in the context of data
- Multi-line expressions are only valid if all expressions con
- Cannot operate inplace if there is no assignment
- Cannot assign expression output to target
- can only assign a single expression
AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07).
Data as JSON: /api/errors/02c7712490254a56.
Report an issue: GitHub.