pandas-dev/pandas · error · ValueError

cannot assign without a target object

Error message

cannot assign without a target object

What it means

visit_Assign checks self.env.target at expr.py:627; if None it raises ValueError. The target is what receives the assignment (target[assigner] = ret at eval.py:437). DataFrame.eval supplies the frame as target automatically, but pd.eval does not — it defaults to target=None.

Source

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

        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
        value = node.value

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Use df.eval('a = b + 1') so the frame is the implicit target.
  2. Pass target explicitly: pd.eval('a = b + 1', target=df).
  3. Pass a dict target if you want the result collected into a namespace.

Example fix

// before
pd.eval('a = b + 1')
// after
df.eval('a = b + 1')
Defensive patterns

Strategy: validation

Validate before calling

import ast

def ensure_target_for_assignment(expr: str, target) -> None:
    has_assign = any(
        isinstance(s, ast.Assign)
        for s in ast.parse(expr, mode='exec').body
    )
    if has_assign and target is None:
        raise ValueError(
            'assignment expression requires a target; use df.eval or pass target='
        )

ensure_target_for_assignment(expr, target)

Type guard

import ast

def assignment_has_target(expr: str, target) -> bool:
    has_assign = any(
        isinstance(s, ast.Assign) for s in ast.parse(expr, mode='exec').body
    )
    return not has_assign or target is not None

Try / catch

try:
    pd.eval(expr)
except ValueError as e:
    if 'without a target' in str(e):
        df.eval(expr)  # switch to DataFrame.eval for the implicit target
    else:
        raise

Prevention

When it happens

Trigger: pd.eval('a = b + 1') with no target kwarg. Any assignment expression routed through pd.eval instead of DataFrame.eval without supplying target.

Common situations: Using pd.eval generically for assignments instead of df.eval. Refactoring df.eval calls into pd.eval and forgetting to forward target.

Related errors


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