HKUDS/Vibe-Trading · error · ValueError
disallowed element in expression: {type(node).__name__}
Error message
disallowed element in expression: {type(node).__name__} What it means
The recursive evaluator _eval_arith_node only accepts Constant, BinOp, and UnaryOp nodes; anything else (Name, Call, Attribute, Compare, etc.) hits the terminal raise. This prevents name lookups and function calls, keeping evaluation side-effect free and exact. The message reports the disallowed AST node type name.
Source
Thrown at agent/src/tools/financial_rigor_tool.py:111
Raises:
ValueError: If the node is not a supported numeric/arithmetic form.
"""
if isinstance(node, ast.Constant):
# bool is a subclass of int — reject it explicitly.
if isinstance(node.value, bool) or not isinstance(node.value, (int, float)):
raise ValueError("only numeric constants are allowed")
return _exact(node.value)
if isinstance(node, ast.BinOp):
op_fn = _AST_BINOPS.get(type(node.op))
if op_fn is None:
raise ValueError(f"unsupported operator: {type(node.op).__name__}")
return op_fn(_eval_arith_node(node.left), _eval_arith_node(node.right))
if isinstance(node, ast.UnaryOp):
op_fn = _AST_UNARYOPS.get(type(node.op))
if op_fn is None:
raise ValueError(f"unsupported unary operator: {type(node.op).__name__}")
return op_fn(_eval_arith_node(node.operand))
raise ValueError(f"disallowed element in expression: {type(node).__name__}")
def _safe_arith(expr: str) -> Decimal:
"""Evaluate a numeric arithmetic expression in the exact-Decimal domain.
The expression is parsed and evaluated recursively with Decimal arithmetic,
so ``0.1 + 0.2`` is exactly ``0.3`` — no IEEE-754 drift, and no ``eval``.
Only numbers and the operators ``+ - * /`` (with optional unary sign) are
permitted; any other AST node raises ``ValueError``.
Args:
expr: Arithmetic expression string, e.g. ``"510 * 9.11e9"``.
Returns:
The exact Decimal result.
Raises:
ValueError: If the expression is malformed or contains a disallowedView on GitHub (pinned to 80ffdda44c)
Solutions
- Inline all values as numeric literals
- Replace function calls with equivalent arithmetic
- If variables are needed, add a controlled name-binding map to the evaluator rather than allowing arbitrary Names
Example fix
// before
_safe_arith("abs(-3) + 2")
// after
_safe_arith("3 + 2") Defensive patterns
Strategy: validation
Validate before calling
import ast
expr = "abs(-1)"
tree = ast.parse(expr, mode="eval")
allowed = (ast.Constant, ast.BinOp, ast.UnaryOp, ast.UAdd, ast.USub,
ast.Add, ast.Sub, ast.Mult, ast.Div, ast.FloorDiv, ast.Mod, ast.Pow)
assert all(isinstance(n, allowed) for n in ast.walk(tree)), "disallowed node present" Type guard
def is_pure_arith(expr: str) -> bool:
import ast
try:
tree = ast.parse(expr, mode="eval")
except SyntaxError:
return False
allowed = (ast.Expression, ast.Constant, ast.BinOp, ast.UnaryOp,
ast.Load, ast.UAdd, ast.USub, ast.Add, ast.Sub, ast.Mult,
ast.Div, ast.FloorDiv, ast.Mod, ast.Pow)
return all(isinstance(n, allowed) for n in ast.walk(tree)) Try / catch
try:
value = _safe_arith(expr)
except ValueError as e:
if "disallowed element" in str(e):
value = None # or fall back to shunting-yard on a numeric tokenizer
else:
raise Prevention
- Inline constants; never pass variable names or calls
- Run is_pure_arith before calling the tool in pipelines
- Keep tool prompts explicit that only literal arithmetic is accepted
When it happens
Trigger: Expressions referencing variables ('pi * 2'), function calls ('abs(-1)'), comparisons ('1 < 2'), tuples, f-strings, or any construct beyond literal arithmetic.
Common situations: LLM tool calls that include helper functions or variable references; users expecting the calculator to accept full Python.
Related errors
- unsupported operator: {type(node.op).__name__}
- unsupported unary operator: {type(node.op).__name__}
- only numeric constants are allowed
- malformed expression: {exc}
- artifact_path escapes the current run_dir
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/9ff489da31eecb32.
Report an issue: GitHub.