FoundationAgents/OpenManus · error · ValueError
Invalid tool_choice: {tool_choice}
Error message
Invalid tool_choice: {tool_choice} What it means
Raised by LLM.ask_with_tools() when the tool_choice argument is not in the module-level TOOL_CHOICE_VALUES constant (typically {"auto", "none", "required"} or the ToolChoice enum values). The validation runs before any message formatting or API call, so it is purely a caller-argument contract check.
Source
Thrown at app/llm.py:678
timeout: Request timeout in seconds
tools: List of tools to use
tool_choice: Tool choice strategy
temperature: Sampling temperature for the response
**kwargs: Additional completion arguments
Returns:
ChatCompletionMessage: The model's response
Raises:
TokenLimitExceeded: If token limits are exceeded
ValueError: If tools, tool_choice, or messages are invalid
OpenAIError: If API call fails after retries
Exception: For unexpected errors
"""
try:
# Validate tool_choice
if tool_choice not in TOOL_CHOICE_VALUES:
raise ValueError(f"Invalid tool_choice: {tool_choice}")
# Check if the model supports images
supports_images = self.model in MULTIMODAL_MODELS
# Format messages
if system_msgs:
system_msgs = self.format_messages(system_msgs, supports_images)
messages = system_msgs + self.format_messages(messages, supports_images)
else:
messages = self.format_messages(messages, supports_images)
# Calculate input token count
input_tokens = self.count_message_tokens(messages)
# If there are tools, calculate token count for tool descriptions
tools_tokens = 0
if tools:
for tool in tools:View on GitHub (pinned to 52a13f2a57)
Solutions
- Use one of the supported values: tool_choice="auto" | "none" | "required" (or the ToolChoice enum)
- If you load tool_choice from config, validate it against TOOL_CHOICE_VALUES at startup
- For named-tool forcing, select the tool yourself before the call — this wrapper does not support it
Example fix
# before
await llm.ask_with_tools(msgs, tools, tool_choice={"type": "function", "function": {"name": "search"}}) # ValueError
# after
await llm.ask_with_tools(msgs, tools=[search_tool], tool_choice="required") Defensive patterns
Strategy: type-guard
Validate before calling
from app.llm import TOOL_CHOICE_VALUES
def valid_tool_choice(tool_choice: str | None) -> bool:
return tool_choice in TOOL_CHOICE_VALUES Type guard
from typing import TypeGuard
from app.llm import TOOL_CHOICE_VALUES
def is_tool_choice(value: object) -> TypeGuard[str]:
return isinstance(value, str) and value in TOOL_CHOICE_VALUES Prevention
- Whitelist config-driven tool_choice values against TOOL_CHOICE_VALUES at startup
- Remember this wrapper accepts only auto/none/required — not OpenAI named-tool objects
- Centralize tool_choice selection in one helper so validation lives in a single place
When it happens
Trigger: Calling ask_with_tools(messages, tools, tool_choice="always"), tool_choice="tool" (OpenAI's named-tool form is not supported here), or passing a non-canonical casing like "Auto". Passing None also fails if None is not among TOOL_CHOICE_VALUES.
Common situations: Copying OpenAI API examples that use named tool choice {"type":"function",...}; assuming arbitrary strings pass through; casing/typo mistakes from config-driven tool_choice values.
Related errors
- Unsupported connection type: {self.connection_type}
- Tool calls required but none provided
- Unknown flow type: {flow_type}
- The last message must be from the user to attach images
- Unsupported image format: {image}
AI-assisted analysis of FoundationAgents/OpenManus@52a13f2a57 (2026-08-15).
Data as JSON: /api/errors/eeee20f0a15d83a2.
Report an issue: GitHub.