{"record":{"id":"71eb5635558b9df2","repo":"BerriAI/litellm","slug":"model-parameter-is-required-71eb56","errorCode":null,"errorMessage":"model parameter is required","messagePattern":"model parameter is required","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"litellm/proxy/anthropic_endpoints/endpoints.py","lineNumber":267,"sourceCode":"        \"model\": \"claude-3-sonnet-20240229\",\n        \"messages\": [{\"role\": \"user\", \"content\": \"Hello Claude!\"}]\n      }'\n    ```\n    \n    Returns: {\"input_tokens\": <number>}\n    \"\"\"\n    from litellm.proxy.proxy_server import token_counter as internal_token_counter\n\n    try:\n        request_data: Final = await _read_request_body(request=request)\n        data: Final[dict] = {**request_data}\n\n        # Extract required fields\n        model_name: Final = data.get(\"model\")\n        messages: Final = data.get(\"messages\", [])\n\n        if not model_name:\n            raise HTTPException(status_code=400, detail={\"error\": \"model parameter is required\"})\n\n        if not messages:\n            raise HTTPException(status_code=400, detail={\"error\": \"messages parameter is required\"})\n\n        # Create TokenCountRequest for the internal endpoint\n        from litellm.proxy._types import TokenCountRequest\n\n        token_request: Final = TokenCountRequest(\n            model=model_name,\n            messages=messages,\n            tools=data.get(\"tools\"),\n            system=data.get(\"system\"),\n        )\n\n        # Call the internal token counter function with direct request flag set to False\n        token_response: Final = await internal_token_counter(\n            request=token_request,\n            call_endpoint=True,","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/anthropic_endpoints/endpoints.py#L249-L285","documentation":"400 from the Anthropic-format token counting endpoint POST /v1/messages/count_tokens (litellm proxy, requires a virtual key via user_api_key_auth). The handler reads the raw JSON body and requires a truthy \"model\" field before building the internal TokenCountRequest; a missing, null, or empty model string fails immediately. The very next check requires non-empty \"messages\", so send both.","triggerScenarios":"POST /v1/messages/count_tokens with a body lacking the model key ({} or {\"messages\": [...]}), with \"model\": null, or with \"model\": \"\". Also when a proxy/gateway in front of LiteLLM strips or renames the field, or when code sends the OpenAI-style prompt field instead of model+messages.","commonSituations":"Calling count_tokens with a hand-rolled request instead of the Anthropic SDK (the SDK forces model); migrating from /utils/token_count with a different body shape; JSON body accidentally sent as form data so parsing yields an empty dict; forwarding a request after popping the model to resolve a deployment.","solutions":["Include a non-empty model plus messages in the JSON body: {\"model\": \"claude-3-sonnet-20240229\", \"messages\": [{\"role\": \"user\", \"content\": \"Hello\"}]} — note messages is checked right after model.","Verify Content-Type: application/json and that the body is not empty/malformed before it reaches the proxy.","If you were using the LiteLLM-internal shape, switch to the Anthropic Messages shape (model/messages/system/tools) that this endpoint mirrors.","Check any middleware that rewrites the body and confirm it preserves the model key."],"exampleFix":"# before\ncurl -X POST http://localhost:4000/v1/messages/count_tokens \\\n  -H \"Authorization: Bearer sk-...\" -H \"Content-Type: application/json\" \\\n  -d '{\"messages\": [{\"role\": \"user\", \"content\": \"Hello\"}]}'\n# -> 400 model parameter is required\n\n# after\ncurl -X POST http://localhost:4000/v1/messages/count_tokens \\\n  -H \"Authorization: Bearer sk-...\" -H \"Content-Type: application/json\" \\\n  -d '{\"model\": \"claude-3-sonnet-20240229\", \"messages\": [{\"role\": \"user\", \"content\": \"Hello\"}]}'","handlingStrategy":"validation","validationCode":"body = {\"model\": model, \"messages\": messages}\nif not body.get(\"model\"):\n    raise ValueError(\"count_tokens requires a non-empty 'model'\")\nif not body.get(\"messages\"):\n    raise ValueError(\"count_tokens requires non-empty 'messages'\")\nresp = client.post(f\"{base}/v1/messages/count_tokens\", json=body, headers=hdr)","typeGuard":"interface CountTokensBody {\n  model: string;\n  messages: Array<{ role: string; content: unknown }>;\n}\nfunction isCountTokensBody(b: unknown): b is CountTokensBody {\n  const o = b as Record<string, unknown>;\n  return typeof o?.model === 'string' && o.model.length > 0 && Array.isArray(o?.messages) && o.messages.length > 0;\n}","tryCatchPattern":"try:\n    resp = client.post(f\"{base}/v1/messages/count_tokens\", json=body, headers=hdr)\n    resp.raise_for_status()\nexcept httpx.HTTPStatusError as e:\n    if e.response.status_code == 400 and \"model parameter is required\" in e.response.text:\n        raise ValueError(\"count_tokens body needs 'model' (and 'messages')\") from e\n    raise","preventionTips":["Prefer the Anthropic SDK's count_tokens method — its typed params make a missing model unrepresentable.","Validate the body has non-empty model and messages before hitting the proxy; the endpoint checks both, in that order.","Log the outbound body shape when integrating custom middleware that may drop fields."],"tags":["litellm-proxy","anthropic","token-counting","validation","http-400","messages-api"],"backgroundTag":"missing-required-parameter","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}