BerriAI/litellm · error · AnthropicError

max_tokens is required for Anthropic /v1/messages API

Error message

max_tokens is required for Anthropic /v1/messages API

What it means

In the Anthropic-to-Anthropic transformation (request already in /v1/messages spec, no translation needed), the handler pops 'max_tokens' from the optional params and rejects requests where it is absent. Unlike OpenAI chat completions, the Anthropic Messages API makes max_tokens mandatory, and litellm enforces that at transformation time with a 400 AnthropicError.

Source

Thrown at litellm/llms/anthropic/experimental_pass_through/messages/transformation.py:495

            optional_params.pop("temperature", None)

    def transform_anthropic_messages_request(
        self,
        model: str,
        messages: list[dict],
        anthropic_messages_optional_request_params: dict,
        litellm_params: GenericLiteLLMParams,
        headers: dict,
    ) -> dict:
        """
        No transformation is needed for Anthropic messages


        This takes in a request in the Anthropic /v1/messages API spec -> transforms it to /v1/messages API spec (i.e) no transformation is needed
        """
        max_tokens: Final = anthropic_messages_optional_request_params.pop("max_tokens", None)
        if max_tokens is None:
            raise AnthropicError(
                message="max_tokens is required for Anthropic /v1/messages API",
                status_code=400,
            )

        self._translate_reasoning_effort_to_anthropic(
            model=model,
            optional_params=anthropic_messages_optional_request_params,
            custom_llm_provider=self._resolved_provider,
        )

        self._translate_legacy_thinking_for_adaptive_model(
            model=model,
            optional_params=anthropic_messages_optional_request_params,
            custom_llm_provider=self._resolved_provider,
        )

        self._translate_adaptive_effort_for_non_adaptive_model(
            model=model,

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Add max_tokens to the request body: e.g. max_tokens=1024 (or 4096+ for reasoning-heavy workloads).
  2. Set a default in your wrapper so every outbound Anthropic-format request carries it.
  3. Budget max_tokens above the model's thinking budget if thinking is enabled, or the upstream call will fail next.

Example fix

# before
body = {"model": "claude-sonnet-4-5", "messages": [{"role": "user", "content": "hi"}]}

# after
body = {"model": "claude-sonnet-4-5", "messages": [{"role": "user", "content": "hi"}], "max_tokens": 1024}
Defensive patterns

Strategy: validation

Validate before calling

def with_max_tokens(body: dict, default_max_tokens: int = 1024) -> dict:
    if not body.get("max_tokens"):
        body = {**body, "max_tokens": default_max_tokens}
    return body

Type guard

def has_max_tokens(body: dict) -> bool:
    mt = body.get("max_tokens")
    return isinstance(mt, int) and not isinstance(mt, bool) and mt > 0

Try / catch

try:
    resp = litellm.anthropic_messages(**body)
except Exception as e:
    if "max_tokens is required" in str(e):
        body["max_tokens"] = 1024
        resp = litellm.anthropic_messages(**body)
    else:
        raise

Prevention

When it happens

Trigger: Sending an Anthropic-format request body without a top-level 'max_tokens' field (None after pop). Typical when porting OpenAI-style calls (where max_tokens is optional) to the anthropic_messages endpoint without adding it.

Common situations: Migrating from litellm.completion (OpenAI params) to anthropic_messages and dropping max_tokens; assuming the gateway injects a default; streaming clients that build minimal bodies.

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/3b2069721e150324. Report an issue: GitHub.