Claude API 400 tool_choice: type "tool" and "any" are not supported for this model: Causes and Fixes
A request to POST /v1/messages (or the token counting endpoint) fails with HTTP 400 invalid_request_error when you pass tool_choice: {"type": "any"} or tool_choice: {"type": "tool", "name": "..."} to a model that does not support forced tool use.
Short answer
Claude Fable 5.2, Claude Mythos 5.2, Claude Opus 5.5, Claude Sonnet 5.5, Claude Fable 5.1, and Claude Mythos 5.1 reject forced tool use (tool_choice type "any" or "tool"). Change tool_choice to {"type": "auto"} (or omit it), add "strict": true to the tool definition with additionalProperties: false and required in input_schema, and name the tool to call in your system prompt. If you only forced a tool call to get a fixed JSON response, switch to structured outputs (output_config.format).
Last verified: 2026-11-14 against Anthropic API Errors — Common validation errors.
Symptoms and What the Error Means
When you send tool_choice: {"type": "any"} or tool_choice: {"type": "tool", "name": "..."} to an affected model — including on the token counting endpoint — the API returns HTTP 400 invalid_request_error with this exact message:
tool_choice: type "tool" and "any" are not supported for this model.In a full error payload:
{
"type": "error",
"error": {
"type": "invalid_request_error",
"message": "tool_choice: type \"tool\" and \"any\" are not supported for this model."
}
}Other 400 validation errors you may hit during the same model upgrade:
- Assistant prefill rejected — see prefill not supported.
- Disabling thinking rejected — see thinking disabled not supported.
- Missing
tool_resultin multi-turn tool calls — see tool_use without tool_result. - Output or thinking token cap errors — see max_tokens too large.
Models Affected
| Model | Forced tool use ("any", "tool") | Accepted tool_choice types |
|---|---|---|
| Claude Fable 5.2 | Not supported (400) | "auto" (default), "none" |
| Claude Mythos 5.2 | Not supported (400) | "auto" (default), "none" |
Claude Opus 5.5 (claude-opus-5-5) | Not supported (400) | "auto" (default), "none" |
Claude Sonnet 5.5 (claude-sonnet-5-5) | Not supported (400) | "auto" (default), "none" |
| Claude Fable 5.1 | Not supported (400) | "auto" (default), "none" |
| Claude Mythos 5.1 | Not supported (400) | "auto" (default), "none" |
Earlier models (e.g., claude-opus-5, claude-opus-4-8, claude-sonnet-5) | Supported | "auto", "any", "tool", "none" |
Why It Happens
- Upgrading the model ID. Code written for earlier models such as
claude-opus-5,claude-opus-4-8, orclaude-sonnet-5works with{"type": "tool", "name": "..."}or{"type": "any"}, then starts failing with HTTP 400 as soon as the model string is changed toclaude-opus-5-5orclaude-sonnet-5-5. - Using a dummy tool for structured JSON extraction. Older integrations often defined a single tool and forced
"type": "tool"to make Claude return schema-matching JSON. - Token counting requests reusing the same body. Passing the same
tool_choiceobject to the token counting endpoint triggers the exact same validation error.
Fix 1: Use tool_choice: {"type": "auto"} with Strict Tool Use
Switch tool_choice to {"type": "auto"} (or omit tool_choice to use the default), enable strict tool use so tool inputs remain schema-valid, and add an explicit instruction in the system prompt naming the tool to call.
For strict tool use:
- Set
"strict": trueas a top-level field on the tool definition (next toname,description, andinput_schema). - Include
"additionalProperties": falseand"required"ininput_schema.
Failing request (POST /v1/messages)
{
"model": "claude-sonnet-5-5",
"max_tokens": 1024,
"tools": [
{
"name": "get_weather",
"description": "Get the current weather for a city.",
"input_schema": {
"type": "object",
"properties": {
"city": { "type": "string" }
},
"required": ["city"]
}
}
],
"tool_choice": {
"type": "tool",
"name": "get_weather"
},
"messages": [
{
"role": "user",
"content": "What is the weather in Tokyo?"
}
]
}Fixed request (POST /v1/messages)
{
"model": "claude-sonnet-5-5",
"max_tokens": 1024,
"system": "Always call the get_weather tool to answer weather questions.",
"tools": [
{
"name": "get_weather",
"description": "Get the current weather for a city.",
"strict": true,
"input_schema": {
"type": "object",
"properties": {
"city": { "type": "string" }
},
"required": ["city"],
"additionalProperties": false
}
}
],
"tool_choice": {
"type": "auto"
},
"messages": [
{
"role": "user",
"content": "What is the weather in Tokyo?"
}
]
}Fix 2: Use Structured Outputs When You Only Need JSON
Anthropic's official guidance notes that if your forced tool call only existed to get the response itself in a fixed JSON shape, you should switch from tools + tool_choice to structured outputs via output_config.format instead of forcing a tool call.
Through a gateway
This HTTP 400 comes from the upstream API's request validation, and an AI API gateway such as byesu passes it through unchanged. Whether you call claude-opus-5-5 or claude-sonnet-5-5 directly or through https://byesu.com, replace "tool" and "any" with {"type": "auto"} or {"type": "none"}. For other errors, see the error index, prompt is too long, or Claude Code custom base URL errors.
FAQ
Which Claude models reject tool_choice "tool" and "any"?
Claude Fable 5.2, Claude Mythos 5.2, Claude Opus 5.5, Claude Sonnet 5.5, Claude Fable 5.1, and Claude Mythos 5.1 do not support forced tool use and return HTTP 400 invalid_request_error when given tool_choice with type "tool" or "any".
Which tool_choice values are accepted on Claude Opus 5.5 and Sonnet 5.5?
Only {"type": "auto"} (the default) and {"type": "none"} are accepted on these models. You can also omit tool_choice to use the default "auto" behavior.
How do I get reliable tool calls or JSON without forced tool use?
Use tool_choice {"type": "auto"} together with strict tool use ("strict": true on the tool definition, with additionalProperties: false and required on input_schema) and an explicit instruction in the system prompt naming the tool to call. If you only forced a tool call to get JSON back, use structured outputs via output_config.format instead.
Does the token counting endpoint also return this 400 error?
Yes. Sending tool_choice {"type": "any"} or {"type": "tool", "name": "..."} for these models on the token counting endpoint returns the exact same HTTP 400 invalid_request_error.
