{"record":{"id":"3b2069721e150324","repo":"BerriAI/litellm","slug":"max-tokens-is-required-for-anthropic-v1-messages","errorCode":null,"errorMessage":"max_tokens is required for Anthropic /v1/messages API","messagePattern":"max_tokens is required for Anthropic /v1/messages API","errorType":"validation","errorClass":"AnthropicError","httpStatus":400,"severity":"error","filePath":"litellm/llms/anthropic/experimental_pass_through/messages/transformation.py","lineNumber":495,"sourceCode":"            optional_params.pop(\"temperature\", None)\n\n    def transform_anthropic_messages_request(\n        self,\n        model: str,\n        messages: list[dict],\n        anthropic_messages_optional_request_params: dict,\n        litellm_params: GenericLiteLLMParams,\n        headers: dict,\n    ) -> dict:\n        \"\"\"\n        No transformation is needed for Anthropic messages\n\n\n        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\n        \"\"\"\n        max_tokens: Final = anthropic_messages_optional_request_params.pop(\"max_tokens\", None)\n        if max_tokens is None:\n            raise AnthropicError(\n                message=\"max_tokens is required for Anthropic /v1/messages API\",\n                status_code=400,\n            )\n\n        self._translate_reasoning_effort_to_anthropic(\n            model=model,\n            optional_params=anthropic_messages_optional_request_params,\n            custom_llm_provider=self._resolved_provider,\n        )\n\n        self._translate_legacy_thinking_for_adaptive_model(\n            model=model,\n            optional_params=anthropic_messages_optional_request_params,\n            custom_llm_provider=self._resolved_provider,\n        )\n\n        self._translate_adaptive_effort_for_non_adaptive_model(\n            model=model,","sourceCodeStart":477,"sourceCodeEnd":513,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/anthropic/experimental_pass_through/messages/transformation.py#L477-L513","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Add max_tokens to the request body: e.g. max_tokens=1024 (or 4096+ for reasoning-heavy workloads).","Set a default in your wrapper so every outbound Anthropic-format request carries it.","Budget max_tokens above the model's thinking budget if thinking is enabled, or the upstream call will fail next."],"exampleFix":"# before\nbody = {\"model\": \"claude-sonnet-4-5\", \"messages\": [{\"role\": \"user\", \"content\": \"hi\"}]}\n\n# after\nbody = {\"model\": \"claude-sonnet-4-5\", \"messages\": [{\"role\": \"user\", \"content\": \"hi\"}], \"max_tokens\": 1024}","handlingStrategy":"validation","validationCode":"def with_max_tokens(body: dict, default_max_tokens: int = 1024) -> dict:\n    if not body.get(\"max_tokens\"):\n        body = {**body, \"max_tokens\": default_max_tokens}\n    return body","typeGuard":"def has_max_tokens(body: dict) -> bool:\n    mt = body.get(\"max_tokens\")\n    return isinstance(mt, int) and not isinstance(mt, bool) and mt > 0","tryCatchPattern":"try:\n    resp = litellm.anthropic_messages(**body)\nexcept Exception as e:\n    if \"max_tokens is required\" in str(e):\n        body[\"max_tokens\"] = 1024\n        resp = litellm.anthropic_messages(**body)\n    else:\n        raise","preventionTips":["Remember max_tokens is mandatory on the Anthropic Messages API (unlike OpenAI).","Set a default in your request builder so every Anthropic-format call carries it.","When thinking is enabled, budget max_tokens above the thinking budget."],"tags":["anthropic","max-tokens","validation","messages-api"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}