BerriAI/litellm · error · ValueError
Incompatible tool choice param submitted - {tool_choice}
Error message
Incompatible tool choice param submitted - {tool_choice} What it means
Raised while translating an Anthropic tool_choice object to the OpenAI format. The translator recognizes exactly four Anthropic tool_choice types — 'auto', 'any', 'none' and 'tool' — and maps them to OpenAI equivalents ('any' maps to 'required'). Any other value in tool_choice['type'] falls through to this ValueError.
Source
Thrown at litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py:710
return reasoning_effort
def translate_anthropic_tool_choice_to_openai(
self, tool_choice: AnthropicMessagesToolChoice
) -> ChatCompletionToolChoiceValues:
if tool_choice["type"] == "any":
return "required"
elif tool_choice["type"] == "auto":
return "auto"
elif tool_choice["type"] == "tool":
# Truncate tool name if it exceeds OpenAI's 64-char limit
original_name: Final = tool_choice.get("name", "")
truncated_name: Final = truncate_tool_name(original_name)
tc_function_param: Final = ChatCompletionToolChoiceFunctionParam(name=truncated_name)
return ChatCompletionToolChoiceObjectParam(type="function", function=tc_function_param)
elif tool_choice["type"] == "none":
return "none"
else:
raise ValueError(f"Incompatible tool choice param submitted - {tool_choice}")
def translate_anthropic_tools_to_openai(
self, tools: list[AllAnthropicToolsValues], model: str | None = None
) -> tuple[list[ChatCompletionToolParam], dict[str, str]]:
"""
Translate Anthropic tools to OpenAI format.
Returns:
Tuple of (translated_tools, tool_name_mapping)
- tool_name_mapping maps truncated names back to original names
for tools that exceeded OpenAI's 64-char limit
"""
new_tools: Final[list[ChatCompletionToolParam]] = []
tool_name_mapping: Final[dict[str, str]] = {}
# "type" is the Anthropic tool type (e.g. "custom"); it must not be
# merged into the OpenAI function `parameters` schema below, or it
# overwrites the real parameters.type ("object") and the provider
# rejects the request. See #30557.View on GitHub (pinned to 6c2dcb801b)
Solutions
- Use one of the four Anthropic tool_choice types: "auto", "any", "none", or "tool" (with a "name" field for "tool").
- If you meant OpenAI semantics, note "any" maps to OpenAI's "required"; for a specific tool use {"type": "tool", "name": "..."}.
- Check exact casing — the match is case-sensitive.
- If Anthropic shipped a new tool_choice type, upgrade litellm to a version that supports it.
Example fix
# before
tool_choice = {"type": "function", "function": {"name": "get_weather"}} # ValueError
# after
tool_choice = {"type": "tool", "name": "get_weather"} Defensive patterns
Strategy: type-guard
Validate before calling
VALID_TOOL_CHOICE_TYPES = {"auto", "any", "none", "tool"}
def validate_tool_choice(tool_choice: dict) -> None:
if tool_choice["type"] not in VALID_TOOL_CHOICE_TYPES:
raise ValueError(f"tool_choice.type must be one of {sorted(VALID_TOOL_CHOICE_TYPES)}")
if tool_choice["type"] == "tool" and not tool_choice.get("name"):
raise ValueError("tool_choice type 'tool' requires a 'name'") Type guard
def is_valid_anthropic_tool_choice(tc: object) -> bool:
return (
isinstance(tc, dict)
and tc.get("type") in {"auto", "any", "none", "tool"}
and (tc["type"] != "tool" or isinstance(tc.get("name"), str) and bool(tc["name"]))
) Try / catch
try:
openai_tc = adapter.translate_anthropic_tool_choice(tool_choice)
except ValueError as e:
if "Incompatible tool choice" in str(e):
return http_error(400, str(e))
raise Prevention
- Never reuse OpenAI tool_choice JSON ({"type": "function", ...}) on Anthropic-format endpoints.
- Centralize tool_choice construction in one helper that only emits the four valid types.
- Check the installed litellm version when Anthropic adds new tool_choice types.
When it happens
Trigger: Sending a tool_choice dict whose 'type' is anything other than auto/any/none/tool, e.g. {"type": "function"} (OpenAI-style value sent to the Anthropic endpoint), {"type": "required"}, or a typo like {"type": "Tool"} (case-sensitive match).
Common situations: Copy-pasting OpenAI tool_choice syntax ({"type": "function", "function": {...}}) into an Anthropic-format request; version drift where a newer Anthropic tool_choice type is not yet supported by the installed litellm; case or spelling mistakes in the type string.
Related errors
- WebSearchInterception: missing follow-up messages
- Invalid first message. Should always start with 'role'='user
- Unable to parse anthropic tool result for message: {message}
- Unable to parse anthropic file message: {message}
- Either file_data or file_id must be present in the file mess
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/8d004f25f015cfc1.
Report an issue: GitHub.