pandas-dev/pandas · error · SyntaxError

left hand side of an assignment must be a single name

Error message

left hand side of an assignment must be a single name

What it means

visit_Assign requires the single target to be an ast.Name (expr.py:625). Subscript assignment ('a[0] = 1') yields an ast.Subscript target and attribute assignment ('a.b = 1') yields an ast.Attribute target, both rejected. Only plain identifier LHS is supported because the assignment path writes target[assigner] = ret with a string key.

Source

Thrown at pandas/core/computation/expr.py:626

        if step is not None:
            step = self.visit(step).value

        return slice(lower, upper, step)

    def visit_Assign(self, node, **kwargs):
        """
        support a single assignment node, like

        c = a + b

        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

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Assign to a column name directly: df.eval('new_col = a + b').
  2. Do cell-level or attribute-level assignment in plain Python (df.loc[i, 'a'] = 1).
  3. Compute the value with eval and assign the result outside the string.

Example fix

// before
df.eval('a[0] = 1')
// after
df.loc[0, 'a'] = 1
Defensive patterns

Strategy: validation

Validate before calling

import ast

def validate_lhs_is_name(expr: str) -> None:
    for stmt in ast.parse(expr, mode='exec').body:
        if isinstance(stmt, ast.Assign) and not isinstance(stmt.targets[0], ast.Name):
            raise SyntaxError(
                'assignment LHS must be a plain name, not a subscript or attribute'
            )

validate_lhs_is_name(expr)

Type guard

import ast

def lhs_is_plain_name(expr: str) -> bool:
    return all(
        not isinstance(s, ast.Assign) or isinstance(s.targets[0], ast.Name)
        for s in ast.parse(expr, mode='exec').body
    )

Try / catch

try:
    df.eval(expr)
except SyntaxError as e:
    if 'single name' in str(e):
        # do the indexed/attr assignment in Python instead
        df.loc[i, 'a'] = value
    raise

Prevention

When it happens

Trigger: df.eval('a[0] = 1'), df.eval('a.b = 1'), df.eval('a["x"] = 1'), or any LHS that is not a bare identifier.

Common situations: Trying to update a single cell or a nested attribute via eval. Porting indexing assignments into the string grammar.

Related errors


AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07). Data as JSON: /api/errors/d7b62d8d83b0188b. Report an issue: GitHub.