{"record":{"id":"38448617387c9430","repo":"huggingface/smolagents","slug":"forbidden-function-evaluation-call-func-id-is","errorCode":null,"errorMessage":"Forbidden function evaluation: '{call.func.id}' is not among the explicitly allowed tools or defined/imported in the preceding code","messagePattern":"Forbidden function evaluation: '(.+?)' is not among the explicitly allowed tools or defined/imported in the preceding code","errorType":"exception","errorClass":"InterpreterError","httpStatus":null,"severity":"error","filePath":"src/smolagents/local_python_executor.py","lineNumber":858,"sourceCode":"        func = evaluate_ast(call.func, state, static_tools, custom_tools, authorized_imports)\n    elif isinstance(call.func, ast.Attribute):\n        obj = evaluate_ast(call.func.value, state, static_tools, custom_tools, authorized_imports)\n        func_name = call.func.attr\n        if not hasattr(obj, func_name):\n            raise InterpreterError(f\"Object {obj} has no attribute {func_name}\")\n        func = getattr(obj, func_name)\n    elif isinstance(call.func, ast.Name):\n        func_name = call.func.id\n        if func_name in state:\n            func = state[func_name]\n        elif func_name in static_tools:\n            func = static_tools[func_name]\n        elif func_name in custom_tools:\n            func = custom_tools[func_name]\n        elif func_name in ERRORS:\n            func = ERRORS[func_name]\n        else:\n            raise InterpreterError(\n                f\"Forbidden function evaluation: '{call.func.id}' is not among the explicitly allowed tools or defined/imported in the preceding code\"\n            )\n    elif isinstance(call.func, ast.Subscript):\n        func = evaluate_ast(call.func, state, static_tools, custom_tools, authorized_imports)\n        if not callable(func):\n            raise InterpreterError(f\"This is not a correct function: {call.func}).\")\n        func_name = None\n\n    args = []\n    for arg in call.args:\n        if isinstance(arg, ast.Starred):\n            args.extend(evaluate_ast(arg.value, state, static_tools, custom_tools, authorized_imports))\n        else:\n            args.append(evaluate_ast(arg, state, static_tools, custom_tools, authorized_imports))\n\n    kwargs = {}\n    for keyword in call.keywords:\n        if keyword.arg is None:","sourceCodeStart":840,"sourceCodeEnd":876,"githubUrl":"https://github.com/huggingface/smolagents/blob/30bb1161095dbae2271e6bc3cc4c219cc3897a57/src/smolagents/local_python_executor.py#L840-L876","documentation":"For a bare-name call f(...), evaluate_call looks the name up in state (code-defined variables/imports), static_tools, custom_tools, and the built-in ERRORS dict; if it is found nowhere, the interpreter treats it as an unauthorized call and raises InterpreterError. This is the sandbox's NameError equivalent with a security rationale: only explicitly provided tools and code-defined/imported names may be called.","triggerScenarios":"Executed code calls a function never defined or imported in the snippet and not among the tools: `print(x)` is fine (builtins) but e.g. `pd.read_csv(...)` without `import pandas as pd`, calling `len` is fine but `search(...)` with no such tool registered, or calling a name defined only in another cell/before a state reset.","commonSituations":"LLM forgets the import line (very common: using np/pd without importing); calling a tool that was not attached to the agent; relying on variables from a previous evaluation after the interpreter state was reset; typo'd function names.","solutions":["Add the missing import inside the executed code (`import pandas as pd` before `pd.read_csv`)","Define the helper inside the snippet, or pass it as a static/custom tool when constructing the agent","Check for typos and ensure the name was assigned earlier in the same snippet (state does not persist across separate evaluate_python calls unless you reuse the interpreter state)"],"exampleFix":"# before\ncode = \"df = pd.read_csv('data.csv')\"\n\n# after\ncode = \"import pandas as pd\\ndf = pd.read_csv('data.csv')\"","handlingStrategy":"validation","validationCode":"import ast\ncode_tree = ast.parse(code)\ndefined = {n.id for n in ast.walk(code_tree) if isinstance(n, ast.Name) and isinstance(n.ctx, ast.Store)}\ndefined |= {n.names[0].asname or n.names[0].name.split('.')[0] for n in ast.walk(code_tree) if isinstance(n, ast.Import)}\ndefined |= {(n.module or '').split('.')[0] for n in ast.walk(code_tree) if isinstance(n, ast.ImportFrom)}\ncalled = {n.func.id for n in ast.walk(code_tree) if isinstance(n, ast.Call) and isinstance(n.func, ast.Name)}\nmissing = called - defined - set(static_tools) - set(custom_tools)\nif missing:\n    raise ValueError(f'undefined names called: {missing}')","typeGuard":null,"tryCatchPattern":"from smolagents.local_python_executor import InterpreterError\ntry:\n    evaluate_python(code, static_tools=static_tools)\nexcept InterpreterError as e:\n    if 'Forbidden function evaluation' in str(e):\n        code = add_missing_imports(code)\n        evaluate_python(code, static_tools=static_tools)","preventionTips":["Require generated code to import everything it uses in the same snippet","Register needed capabilities as static/custom tools up front","Remember interpreter state resets between runs — redefine helpers each snippet"],"tags":["smolagents","name-resolution","unauthorized-call","missing-import","sandbox"],"backgroundTag":"undefined-name-in-sandbox","analyzedSha":"30bb1161095dbae2271e6bc3cc4c219cc3897a57","analyzedAt":"2026-08-28T18:52:54.169Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}