pandas-dev/pandas · error · ValueError
Multi-line expressions are only valid if all expressions con
Error message
Multi-line expressions are only valid if all expressions contain an assignment
What it means
When a multi-line expression is allowed (target supplied), every sub-expression must be an assignment because the loop in eval.py:361 assigns sequentially and only the final return value is non-None. If any line is a bare expression (parsed_expr.assigner is None at eval.py:402), there is no column to assign and no meaningful return, so pandas raises. This keeps multi-line semantics unambiguous.
Source
Thrown at pandas/core/computation/eval.py:404
)
)
):
warnings.warn(
"Engine has switched to 'python' because numexpr does not support "
"extension array dtypes. Please set your engine to python manually.",
RuntimeWarning,
stacklevel=find_stack_level(),
)
engine = "python"
# construct the engine and evaluate the parsed expression
eng = ENGINES[engine]
eng_inst = eng(parsed_expr)
ret = eng_inst.evaluate()
if parsed_expr.assigner is None:
if multi_line:
raise ValueError(
"Multi-line expressions are only valid "
"if all expressions contain an assignment"
)
if inplace:
raise ValueError("Cannot operate inplace if there is no assignment")
# assign if needed
assigner = parsed_expr.assigner
if env.target is not None and assigner is not None:
target_modified = True
# if returning a copy, copy only on the first assignment
if not inplace and first_expr:
try:
target = env.target
if isinstance(target, NDFrame):
target = target.copy(deep=False)
else:View on GitHub (pinned to 71959b8cb9)
Solutions
- Make every line an assignment, e.g. df.eval('a = b + 1\nc = b + 2').
- Move the bare expression into a separate, single-line df.eval/df.query call.
- Capture the bare line's result by assigning it to a new column.
Example fix
// before
df.eval('a = b + 1\nb + 2')
// after
df.eval('a = b + 1\nc = b + 2') Defensive patterns
Strategy: validation
Validate before calling
def validate_multiline_all_assigned(expr: str) -> None:
import ast
for line in (l for l in expr.splitlines() if l.strip()):
tree = ast.parse(line, mode='exec')
if not any(isinstance(n, ast.Assign) for n in tree.body):
raise ValueError(
f'Every multi-line expression must assign; offending line: {line!r}'
)
validate_multiline_all_assigned(multiline_expr) Type guard
import ast
def all_lines_assign(expr: str) -> bool:
return all(
any(isinstance(n, ast.Assign) for n in ast.parse(l, mode='exec').body)
for l in (s for s in expr.splitlines() if s.strip())
) Try / catch
try:
df.eval(expr)
except ValueError as e:
if 'must contain an assignment' in str(e):
# split assignment lines from any bare expression and handle separately
...
raise Prevention
- Author multi-line eval strings with one assignment per line.
- Run a quick ast.parse check on each line when generating strings programmatically.
- Avoid appending a 'return' line to assignment blocks.
When it happens
Trigger: df.eval('a = b + 1\nb + 2') — the second line has no '='. Any multi-line df.eval string where at least one line is a pure expression rather than an assignment.
Common situations: Appending a final 'return' line to a sequence of assignments expecting it to be yielded. Mixing query-style filters with column assignments in one string.
Related errors
- multi-line expressions are only valid in the context of data
- Cannot operate inplace if there is no assignment
- Cannot assign expression output to target
- can only assign a single expression
- left hand side of an assignment must be a single name
AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07).
Data as JSON: /api/errors/65f07ed9f466e0f9.
Report an issue: GitHub.