huggingface/smolagents · error · InterpreterError

Cannot assign to name

Error message

Cannot assign to name '{target.id}': doing this would erase the existing tool!

What it means

set_value refuses ast.Name assignments whose id collides with a key in static_tools: overwriting would shadow/remove a registered tool for the rest of the execution. The executor raises InterpreterError telling you the assignment would erase the tool.

Solutions

  1. Rename the variable in the generated code to something non-colliding (e.g. search_result instead of search)
  2. Rename the custom tool to a less generic name when registering it
  3. Prompt the agent with the list of reserved tool names and instruct it to avoid them as identifiers

Example fix

# before
code = "search = 'query text'\nfinal_answer(search)"

# after
code = "search_query = 'query text'\nfinal_answer(search_query)"
Defensive patterns

Strategy: validation

Validate before calling

import ast
reserved = set(static_tools)  # e.g. {'search', 'final_answer'}
for node in ast.walk(ast.parse(code)):
    names = set()
    if isinstance(node, (ast.Assign, ast.AnnAssign, ast.AugAssign)):
        targets = node.targets if isinstance(node, ast.Assign) else [node.target]
        names |= {t.id for t in targets if isinstance(t, ast.Name)}
    if isinstance(node, (ast.For, ast.comprehension)):
        names |= {n.id for n in ast.walk(node.target) if isinstance(n, ast.Name)}
    clash = names & reserved
    if clash:
        raise ValueError(f'variable names shadow tools: {clash}')

Try / catch

from smolagents.local_python_executor import InterpreterError
try:
    evaluate_python(code, static_tools=static_tools)
except InterpreterError as e:
    if 'would erase the existing tool' in str(e):
        code = rename_shadowed_vars(code, avoid=set(static_tools))
        evaluate_python(code, static_tools=static_tools)

Prevention

When it happens

Trigger: Executed code assigns to a name that is a static tool: e.g. with a registered tool named 'search', code containing `search = 'foo'`, `search, x = 1, 2`, or a for-loop target/comprehension variable named `search`. The check applies to Assign, AnnAssign, AugAssign targets, for-loops and comprehensions.

Common situations: LLM picks a generic variable name that matches a tool name ('search', 'final_answer', 'visit_webpage'); tuple unpacking or iteration reuses a tool name; user names their custom tool something common like 'read' or 'get'.

Related errors


AI-assisted analysis of huggingface/smolagents@30bb116109 (2026-08-28). Data as JSON: /api/errors/2de99f20cf6efde6. Report an issue: GitHub.

Appendix: source

Thrown at src/smolagents/local_python_executor.py:804

            else:
                expanded_values.append(result)

        for tgt, val in zip(assign.targets, expanded_values):
            set_value(tgt, val, state, static_tools, custom_tools, authorized_imports)
    return result


def set_value(
    target: ast.AST,
    value: Any,
    state: dict[str, Any],
    static_tools: dict[str, Callable],
    custom_tools: dict[str, Callable],
    authorized_imports: list[str],
) -> None:
    if isinstance(target, ast.Name):
        if target.id in static_tools:
            raise InterpreterError(f"Cannot assign to name '{target.id}': doing this would erase the existing tool!")
        state[target.id] = value
    elif isinstance(target, ast.Tuple):
        if not isinstance(value, tuple):
            if hasattr(value, "__iter__") and not isinstance(value, (str, bytes)):
                value = tuple(value)
            else:
                raise InterpreterError("Cannot unpack non-tuple value")
        if len(target.elts) != len(value):
            raise InterpreterError("Cannot unpack tuple of wrong size")
        for i, elem in enumerate(target.elts):
            set_value(elem, value[i], state, static_tools, custom_tools, authorized_imports)
    elif isinstance(target, ast.Subscript):
        obj = evaluate_ast(target.value, state, static_tools, custom_tools, authorized_imports)
        key = evaluate_ast(target.slice, state, static_tools, custom_tools, authorized_imports)
        obj[key] = value
    elif isinstance(target, ast.Attribute):
        obj = evaluate_ast(target.value, state, static_tools, custom_tools, authorized_imports)
        setattr(obj, target.attr, value)

View on GitHub (pinned to 30bb116109)