microsoft/autogen · error · ValueError

Tool names must be unique: {tool_names}

Error message

Tool names must be unique: {tool_names}

What it means

After collecting tools, AssistantAgent verifies that all tool names are unique; duplicates raise ValueError listing the full name list. Names come from BaseTool.name or the function name for plain callables.

Source

Thrown at python/packages/autogen-agentchat/src/autogen_agentchat/agents/_assistant_agent.py:789

        self._tools: List[BaseTool[Any, Any]] = []
        if tools is not None:
            if model_client.model_info["function_calling"] is False:
                raise ValueError("The model does not support function calling.")
            for tool in tools:
                if isinstance(tool, BaseTool):
                    self._tools.append(tool)
                elif callable(tool):
                    if hasattr(tool, "__doc__") and tool.__doc__ is not None:
                        description = tool.__doc__
                    else:
                        description = ""
                    self._tools.append(FunctionTool(tool, description=description))
                else:
                    raise ValueError(f"Unsupported tool type: {type(tool)}")
        # Check if tool names are unique.
        tool_names = [tool.name for tool in self._tools]
        if len(tool_names) != len(set(tool_names)):
            raise ValueError(f"Tool names must be unique: {tool_names}")

        # Handoff tools.
        self._handoff_tools: List[BaseTool[Any, Any]] = []
        self._handoffs: Dict[str, HandoffBase] = {}
        if handoffs is not None:
            if model_client.model_info["function_calling"] is False:
                raise ValueError("The model does not support function calling, which is needed for handoffs.")
            for handoff in handoffs:
                if isinstance(handoff, str):
                    handoff = HandoffBase(target=handoff)
                if isinstance(handoff, HandoffBase):
                    self._handoff_tools.append(handoff.handoff_tool)
                    self._handoffs[handoff.name] = handoff
                else:
                    raise ValueError(f"Unsupported handoff type: {type(handoff)}")
        # Check if handoff tool names are unique.
        handoff_tool_names = [tool.name for tool in self._handoff_tools]
        if len(handoff_tool_names) != len(set(handoff_tool_names)):

View on GitHub (pinned to 027ecf0a37)

Solutions

  1. De-duplicate the tools list before passing it (see validation snippet).
  2. Rename colliding tools via FunctionTool(func, name=...) or your BaseTool subclass's name field.
  3. Print [t.name for t in tools] to spot the duplicate quickly.

Example fix

# before
agent = AssistantAgent(name="a", model_client=client, tools=[search_web, search_web])

# after
seen, unique_tools = set(), []
for t in tools:
    n = t.name if hasattr(t, "name") else t.__name__
    if n not in seen:
        seen.add(n)
        unique_tools.append(t)
agent = AssistantAgent(name="a", model_client=client, tools=unique_tools)
Defensive patterns

Strategy: validation

Validate before calling

names = [t.name if hasattr(t, "name") else getattr(t, "__name__", str(t)) for t in tools]
dupes = {n for n in names if names.count(n) > 1}
if dupes:
    raise ValueError(f"duplicate tool names: {dupes}")

Type guard

def has_unique_tool_names(tools) -> bool:
    names = [t.name if hasattr(t, "name") else t.__name__ for t in tools]
    return len(names) == len(set(names))

Try / catch

try:
    agent = AssistantAgent(name="a", model_client=client, tools=tools)
except ValueError as e:
    if "must be unique" in str(e):
        seen, uniq = set(), []
        for t in tools:
            n = t.name if hasattr(t, "name") else t.__name__
            if n not in seen:
                seen.add(n); uniq.append(t)
        agent = AssistantAgent(name="a", model_client=client, tools=uniq)
    else:
        raise

Prevention

When it happens

Trigger: Registering the same tool twice, two different tools with the same name attribute, or two plain functions with the same __name__ (e.g. both named 'search'), or passing the same FunctionTool under different wrappers.

Common situations: Programmatically building tool lists where the same tool is appended in a loop, refactors that rename tools into collisions, or merging tool sets from multiple modules with generic names like 'get' or 'run'.

Related errors


AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15). Data as JSON: /api/errors/b6b1917d3e955064. Report an issue: GitHub.