pandas-dev/pandas · error · SyntaxError
only a single expression is allowed
Error message
only a single expression is allowed
What it means
visit_Module (expr.py:422) requires exactly one element in node.body. If Python's parser produces a module with multiple statements (e.g. from semicolon-chained statements parsed in a single Expr call, or a stray extra statement), the visitor refuses. eval.py already splits on newlines, so this fires mainly when a single preparser pass yields multiple top-level statements.
Source
Thrown at pandas/core/computation/expr.py:424
self.assigner = None
def visit(self, node, **kwargs):
if isinstance(node, str):
clean = self.preparser(node)
try:
node = ast.fix_missing_locations(ast.parse(clean))
except SyntaxError as e:
if any(iskeyword(x) for x in clean.split()):
e.msg = "Python keyword not valid identifier in numexpr query"
raise e
method = f"visit_{type(node).__name__}"
visitor = getattr(self, method)
return visitor(node, **kwargs)
def visit_Module(self, node, **kwargs):
if len(node.body) != 1:
raise SyntaxError("only a single expression is allowed")
expr = node.body[0]
return self.visit(expr, **kwargs)
def visit_Expr(self, node, **kwargs):
return self.visit(node.value, **kwargs)
def _rewrite_membership_op(self, node, left, right):
# the kind of the operator (is actually an instance)
op_instance = node.op
op_type = type(op_instance)
# must be two terms and the comparison operator must be ==/!=/in/not in
if is_term(left) and is_term(right) and op_type in self.rewrite_map:
left_list, right_list = map(_is_list, (left, right))
left_str, right_str = map(_is_str, (left, right))
# if there are any strings or lists in the expression
if left_list or right_list or left_str or right_str:View on GitHub (pinned to 71959b8cb9)
Solutions
- Split the string into one expression per eval call.
- Replace ';' chaining with separate DataFrame.eval invocations.
- If building expressions programmatically, validate they parse to a single ast.Expr before passing.
Example fix
// before
pd.eval('a + 1; b + 2')
// after
[a + 1, b + 2] # or two separate pd.eval calls Defensive patterns
Strategy: validation
Validate before calling
import ast
def validate_single_expression(expr: str) -> None:
tree = ast.parse(expr, mode='exec')
if len(tree.body) != 1:
raise SyntaxError(
f'expected a single expression, got {len(tree.body)} statements'
)
validate_single_expression(expr) Type guard
import ast
def is_single_expression(expr: str) -> bool:
return len(ast.parse(expr, mode='exec').body) == 1 Try / catch
try:
pd.eval(expr)
except SyntaxError as e:
if 'single expression' in str(e):
for stmt in expr.split(';'):
pd.eval(stmt.strip())
else:
raise Prevention
- One expression per eval call; avoid ';'-chaining.
- When generating strings programmatically, assert they parse to a single statement.
- Split compound user input into separate eval invocations.
When it happens
Trigger: An expression string that parses to more than one top-level statement within a single Expr.visit, e.g. an embedded ';' producing two statements after preprocessing, or a statement followed by an expression.
Common situations: Embedding ';'-separated statements assuming eval handles them like Python. Preparser rewrites that accidentally introduce a second statement. Internal recursive eval calls where a sub-expression parses to multiple statements.
Related errors
- The '@' prefix is only supported by the pandas parser
- '{node_name}' nodes are not implemented
- can only assign a single expression
- left hand side of an assignment must be a single name
- keyword error in function call '{node.func.id}'
AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07).
Data as JSON: /api/errors/9510dc65fb1627db.
Report an issue: GitHub.