{"record":{"id":"b6b1917d3e955064","repo":"microsoft/autogen","slug":"tool-names-must-be-unique-tool-names","errorCode":null,"errorMessage":"Tool names must be unique: {tool_names}","messagePattern":"Tool names must be unique: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/packages/autogen-agentchat/src/autogen_agentchat/agents/_assistant_agent.py","lineNumber":789,"sourceCode":"        self._tools: List[BaseTool[Any, Any]] = []\n        if tools is not None:\n            if model_client.model_info[\"function_calling\"] is False:\n                raise ValueError(\"The model does not support function calling.\")\n            for tool in tools:\n                if isinstance(tool, BaseTool):\n                    self._tools.append(tool)\n                elif callable(tool):\n                    if hasattr(tool, \"__doc__\") and tool.__doc__ is not None:\n                        description = tool.__doc__\n                    else:\n                        description = \"\"\n                    self._tools.append(FunctionTool(tool, description=description))\n                else:\n                    raise ValueError(f\"Unsupported tool type: {type(tool)}\")\n        # Check if tool names are unique.\n        tool_names = [tool.name for tool in self._tools]\n        if len(tool_names) != len(set(tool_names)):\n            raise ValueError(f\"Tool names must be unique: {tool_names}\")\n\n        # Handoff tools.\n        self._handoff_tools: List[BaseTool[Any, Any]] = []\n        self._handoffs: Dict[str, HandoffBase] = {}\n        if handoffs is not None:\n            if model_client.model_info[\"function_calling\"] is False:\n                raise ValueError(\"The model does not support function calling, which is needed for handoffs.\")\n            for handoff in handoffs:\n                if isinstance(handoff, str):\n                    handoff = HandoffBase(target=handoff)\n                if isinstance(handoff, HandoffBase):\n                    self._handoff_tools.append(handoff.handoff_tool)\n                    self._handoffs[handoff.name] = handoff\n                else:\n                    raise ValueError(f\"Unsupported handoff type: {type(handoff)}\")\n        # Check if handoff tool names are unique.\n        handoff_tool_names = [tool.name for tool in self._handoff_tools]\n        if len(handoff_tool_names) != len(set(handoff_tool_names)):","sourceCodeStart":771,"sourceCodeEnd":807,"githubUrl":"https://github.com/microsoft/autogen/blob/027ecf0a379bcc1d09956d46d12d44a3ad9cee14/python/packages/autogen-agentchat/src/autogen_agentchat/agents/_assistant_agent.py#L771-L807","documentation":"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.","triggerScenarios":"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.","commonSituations":"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'.","solutions":["De-duplicate the tools list before passing it (see validation snippet).","Rename colliding tools via FunctionTool(func, name=...) or your BaseTool subclass's name field.","Print [t.name for t in tools] to spot the duplicate quickly."],"exampleFix":"# before\nagent = AssistantAgent(name=\"a\", model_client=client, tools=[search_web, search_web])\n\n# after\nseen, unique_tools = set(), []\nfor t in tools:\n    n = t.name if hasattr(t, \"name\") else t.__name__\n    if n not in seen:\n        seen.add(n)\n        unique_tools.append(t)\nagent = AssistantAgent(name=\"a\", model_client=client, tools=unique_tools)","handlingStrategy":"validation","validationCode":"names = [t.name if hasattr(t, \"name\") else getattr(t, \"__name__\", str(t)) for t in tools]\ndupes = {n for n in names if names.count(n) > 1}\nif dupes:\n    raise ValueError(f\"duplicate tool names: {dupes}\")","typeGuard":"def has_unique_tool_names(tools) -> bool:\n    names = [t.name if hasattr(t, \"name\") else t.__name__ for t in tools]\n    return len(names) == len(set(names))","tryCatchPattern":"try:\n    agent = AssistantAgent(name=\"a\", model_client=client, tools=tools)\nexcept ValueError as e:\n    if \"must be unique\" in str(e):\n        seen, uniq = set(), []\n        for t in tools:\n            n = t.name if hasattr(t, \"name\") else t.__name__\n            if n not in seen:\n                seen.add(n); uniq.append(t)\n        agent = AssistantAgent(name=\"a\", model_client=client, tools=uniq)\n    else:\n        raise","preventionTips":["Deduplicate tool lists at build time with dict.fromkeys-style logic keyed by name.","Give every tool an explicit, namespaced name attribute."],"tags":["python","tools","uniqueness","validation","autogen"],"backgroundTag":null,"analyzedSha":"027ecf0a379bcc1d09956d46d12d44a3ad9cee14","analyzedAt":"2026-08-15T03:38:00.719Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}