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

  1. Use one of the supported values: tool_choice="auto" | "none" | "required" (or the ToolChoice enum)
  2. If you load tool_choice from config, validate it against TOOL_CHOICE_VALUES at startup
  3. 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

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


AI-assisted analysis of FoundationAgents/OpenManus@52a13f2a57 (2026-08-15). Data as JSON: /api/errors/eeee20f0a15d83a2. Report an issue: GitHub.