{"record":{"id":"ad5c0bc6b8c8942e","repo":"pandas-dev/pandas","slug":"cannot-assign-without-a-target-object","errorCode":null,"errorMessage":"cannot assign without a target object","messagePattern":"cannot assign without a target object","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"pandas/core/computation/expr.py","lineNumber":628,"sourceCode":"\n        return slice(lower, upper, step)\n\n    def visit_Assign(self, node, **kwargs):\n        \"\"\"\n        support a single assignment node, like\n\n        c = a + b\n\n        set the assigner at the top level, must be a Name node which\n        might or might not exist in the resolvers\n\n        \"\"\"\n        if len(node.targets) != 1:\n            raise SyntaxError(\"can only assign a single expression\")\n        if not isinstance(node.targets[0], ast.Name):\n            raise SyntaxError(\"left hand side of an assignment must be a single name\")\n        if self.env.target is None:\n            raise ValueError(\"cannot assign without a target object\")\n\n        try:\n            assigner = self.visit(node.targets[0], **kwargs)\n        except UndefinedVariableError:\n            assigner = node.targets[0].id\n\n        self.assigner = getattr(assigner, \"name\", assigner)\n        if self.assigner is None:\n            raise SyntaxError(\n                \"left hand side of an assignment must be a single resolvable name\"\n            )\n\n        return self.visit(node.value, **kwargs)\n\n    def visit_Attribute(self, node, **kwargs):\n        attr = node.attr\n        value = node.value\n","sourceCodeStart":610,"sourceCodeEnd":646,"githubUrl":"https://github.com/pandas-dev/pandas/blob/71959b8cb9b2459c16e14b34f28b178ccfe14735/pandas/core/computation/expr.py#L610-L646","documentation":"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.","triggerScenarios":"pd.eval('a = b + 1') with no target kwarg. Any assignment expression routed through pd.eval instead of DataFrame.eval without supplying target.","commonSituations":"Using pd.eval generically for assignments instead of df.eval. Refactoring df.eval calls into pd.eval and forgetting to forward target.","solutions":["Use df.eval('a = b + 1') so the frame is the implicit target.","Pass target explicitly: pd.eval('a = b + 1', target=df).","Pass a dict target if you want the result collected into a namespace."],"exampleFix":"// before\npd.eval('a = b + 1')\n// after\ndf.eval('a = b + 1')","handlingStrategy":"validation","validationCode":"import ast\n\ndef ensure_target_for_assignment(expr: str, target) -> None:\n    has_assign = any(\n        isinstance(s, ast.Assign)\n        for s in ast.parse(expr, mode='exec').body\n    )\n    if has_assign and target is None:\n        raise ValueError(\n            'assignment expression requires a target; use df.eval or pass target='\n        )\n\nensure_target_for_assignment(expr, target)","typeGuard":"import ast\n\ndef assignment_has_target(expr: str, target) -> bool:\n    has_assign = any(\n        isinstance(s, ast.Assign) for s in ast.parse(expr, mode='exec').body\n    )\n    return not has_assign or target is not None","tryCatchPattern":"try:\n    pd.eval(expr)\nexcept ValueError as e:\n    if 'without a target' in str(e):\n        df.eval(expr)  # switch to DataFrame.eval for the implicit target\n    else:\n        raise","preventionTips":["Use DataFrame.eval for any assignment expression.","If calling pd.eval with an assignment, always pass target=.","Wrap assignment eval calls in a helper that injects the frame as target."],"tags":["pandas","eval","target","assignment"],"analyzedSha":"71959b8cb9b2459c16e14b34f28b178ccfe14735","analyzedAt":"2026-08-07T01:30:20.476Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}