{"record":{"id":"9ff489da31eecb32","repo":"HKUDS/Vibe-Trading","slug":"disallowed-element-in-expression-type-node-na","errorCode":null,"errorMessage":"disallowed element in expression: {type(node).__name__}","messagePattern":"disallowed element in expression: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/tools/financial_rigor_tool.py","lineNumber":111,"sourceCode":"    Raises:\n        ValueError: If the node is not a supported numeric/arithmetic form.\n    \"\"\"\n    if isinstance(node, ast.Constant):\n        # bool is a subclass of int — reject it explicitly.\n        if isinstance(node.value, bool) or not isinstance(node.value, (int, float)):\n            raise ValueError(\"only numeric constants are allowed\")\n        return _exact(node.value)\n    if isinstance(node, ast.BinOp):\n        op_fn = _AST_BINOPS.get(type(node.op))\n        if op_fn is None:\n            raise ValueError(f\"unsupported operator: {type(node.op).__name__}\")\n        return op_fn(_eval_arith_node(node.left), _eval_arith_node(node.right))\n    if isinstance(node, ast.UnaryOp):\n        op_fn = _AST_UNARYOPS.get(type(node.op))\n        if op_fn is None:\n            raise ValueError(f\"unsupported unary operator: {type(node.op).__name__}\")\n        return op_fn(_eval_arith_node(node.operand))\n    raise ValueError(f\"disallowed element in expression: {type(node).__name__}\")\n\n\ndef _safe_arith(expr: str) -> Decimal:\n    \"\"\"Evaluate a numeric arithmetic expression in the exact-Decimal domain.\n\n    The expression is parsed and evaluated recursively with Decimal arithmetic,\n    so ``0.1 + 0.2`` is exactly ``0.3`` — no IEEE-754 drift, and no ``eval``.\n    Only numbers and the operators ``+ - * /`` (with optional unary sign) are\n    permitted; any other AST node raises ``ValueError``.\n\n    Args:\n        expr: Arithmetic expression string, e.g. ``\"510 * 9.11e9\"``.\n\n    Returns:\n        The exact Decimal result.\n\n    Raises:\n        ValueError: If the expression is malformed or contains a disallowed","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/tools/financial_rigor_tool.py#L93-L129","documentation":"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.","triggerScenarios":"Expressions referencing variables ('pi * 2'), function calls ('abs(-1)'), comparisons ('1 < 2'), tuples, f-strings, or any construct beyond literal arithmetic.","commonSituations":"LLM tool calls that include helper functions or variable references; users expecting the calculator to accept full Python.","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"],"exampleFix":"// before\n_safe_arith(\"abs(-3) + 2\")\n// after\n_safe_arith(\"3 + 2\")","handlingStrategy":"validation","validationCode":"import ast\nexpr = \"abs(-1)\"\ntree = ast.parse(expr, mode=\"eval\")\nallowed = (ast.Constant, ast.BinOp, ast.UnaryOp, ast.UAdd, ast.USub,\n           ast.Add, ast.Sub, ast.Mult, ast.Div, ast.FloorDiv, ast.Mod, ast.Pow)\nassert all(isinstance(n, allowed) for n in ast.walk(tree)), \"disallowed node present\"","typeGuard":"def is_pure_arith(expr: str) -> bool:\n    import ast\n    try:\n        tree = ast.parse(expr, mode=\"eval\")\n    except SyntaxError:\n        return False\n    allowed = (ast.Expression, ast.Constant, ast.BinOp, ast.UnaryOp,\n               ast.Load, ast.UAdd, ast.USub, ast.Add, ast.Sub, ast.Mult,\n               ast.Div, ast.FloorDiv, ast.Mod, ast.Pow)\n    return all(isinstance(n, allowed) for n in ast.walk(tree))","tryCatchPattern":"try:\n    value = _safe_arith(expr)\nexcept ValueError as e:\n    if \"disallowed element\" in str(e):\n        value = None  # or fall back to shunting-yard on a numeric tokenizer\n    else:\n        raise","preventionTips":["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"],"tags":["python","ast","sandbox","expression-eval","security"],"backgroundTag":"expression-not-allowed","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}