Skip to content

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:

text
tool_choice: type "tool" and "any" are not supported for this model.

In a full error payload:

json
{
  "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:

Models Affected ​

ModelForced tool use ("any", "tool")Accepted tool_choice types
Claude Fable 5.2Not supported (400)"auto" (default), "none"
Claude Mythos 5.2Not 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.1Not supported (400)"auto" (default), "none"
Claude Mythos 5.1Not 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 ​

  1. Upgrading the model ID. Code written for earlier models such as claude-opus-5, claude-opus-4-8, or claude-sonnet-5 works with {"type": "tool", "name": "..."} or {"type": "any"}, then starts failing with HTTP 400 as soon as the model string is changed to claude-opus-5-5 or claude-sonnet-5-5.
  2. 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.
  3. Token counting requests reusing the same body. Passing the same tool_choice object 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": true as a top-level field on the tool definition (next to name, description, and input_schema).
  • Include "additionalProperties": false and "required" in input_schema.

Failing request (POST /v1/messages) ​

json
{
  "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) ​

json
{
  "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.

Got a problem? Contact support or join our group.