microsoft/autogen · error · ValueError
tool_choice specified but no tools provided
Error message
tool_choice specified but no tools provided
What it means
Thrown by OpenAIChatCompletionClient when the tool_choice parameter is a Tool instance but the tools list is empty. A specific tool_choice forces the model to call a named tool, which is meaningless if no tools are provided, so the client rejects the combination immediately.
Source
Thrown at python/packages/autogen-ext/src/autogen_ext/models/openai/_openai_client.py:636
prepend_name=self._add_name_prefixes,
model=create_args.get("model", "unknown"),
model_family=self._model_info["family"],
include_name_in_message=self._include_name_in_message,
)
for m in messages
]
oai_messages = [item for sublist in oai_messages_nested for item in sublist]
if self.model_info["function_calling"] is False and len(tools) > 0:
raise ValueError("Model does not support function calling")
converted_tools = convert_tools(tools)
# Process tool_choice parameter
if isinstance(tool_choice, Tool):
if len(tools) == 0:
raise ValueError("tool_choice specified but no tools provided")
# Validate that the tool exists in the provided tools
tool_names_available: List[str] = []
for tool in tools:
if isinstance(tool, Tool):
tool_names_available.append(tool.schema["name"])
else:
tool_names_available.append(tool["name"])
# tool_choice is a single Tool object
tool_name = tool_choice.schema["name"]
if tool_name not in tool_names_available:
raise ValueError(f"tool_choice references '{tool_name}' but it's not in the provided tools")
if len(converted_tools) > 0:
# Convert to OpenAI format and add to create_args
converted_tool_choice = convert_tool_choice(tool_choice)
create_args["tool_choice"] = converted_tool_choiceView on GitHub (pinned to 027ecf0a37)
Solutions
- Pass the referenced tool in the tools list: tools=[tool_choice, ...]
- Skip setting tool_choice (or set it to 'none') when the tools list is empty
- Guard at the call site: only set a Tool tool_choice when len(tools) > 0
Example fix
# before await client.create([msg], tools=[], tool_choice=required_tool) # after await client.create([msg], tools=[required_tool], tool_choice=required_tool)
Defensive patterns
Strategy: validation
Validate before calling
from autogen_core.tools import Tool
if isinstance(tool_choice, Tool):
assert tools, "tool_choice Tool requires a non-empty tools list"
assert tool_choice in tools or tool_choice.schema["name"] in {getattr(t, 'schema', t)['name'] for t in tools} Type guard
def tool_choice_is_consistent(tool_choice, tools) -> bool:
if not isinstance(tool_choice, Tool):
return True
names = {t.schema["name"] if isinstance(t, Tool) else t["name"] for t in tools}
return len(tools) > 0 and tool_choice.schema["name"] in names Try / catch
try:
result = await client.create(messages, tools=tools, tool_choice=tool_choice)
except ValueError as e:
if "tool_choice" in str(e):
result = await client.create(messages, tools=tools, tool_choice="auto")
else:
raise Prevention
- Derive tool_choice from the same tools list you pass — never two independent sources
- Default tool_choice to 'auto' and only force a Tool when the list is provably non-empty
- Log the tools/tool_choice pair before each call during development
When it happens
Trigger: Calling create with tool_choice=some_tool (a Tool object, not the string 'auto'/'required'/'none') while tools=[] or tools is omitted. String literals like 'auto' do not trigger this; only a Tool instance with an empty tools list does.
Common situations: Dynamically building a tools list that ends up empty (a filter removed everything) while a hardcoded tool_choice Tool is still passed; refactoring code that previously passed a non-empty tool set; agent frameworks forwarding a stale tool_choice.
Related errors
- tool_choice references '{tool_name}' but it's not in the pro
- Unsupported tool type: {type(tool)}
- Tool '{tool_name}' requires specific parameters and cannot b
- Unsupported built-in tool type: {tool_name}
- Unsupported tool type: {type(tool)}
AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15).
Data as JSON: /api/errors/c34c00c43bf8d84a.
Report an issue: GitHub.