HKUDS/Vibe-Trading · error · ValueError

disallowed element in expression

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.

Solutions

  1. Inline all values as numeric literals
  2. Replace function calls with equivalent arithmetic
  3. 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

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


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/9ff489da31eecb32. Report an issue: GitHub.

Appendix: 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 disallowed

View on GitHub (pinned to 80ffdda44c)