{"record":{"id":"8658ba8bf56cb3e9","repo":"BerriAI/litellm","slug":"messages-parameter-is-required-8658ba","errorCode":null,"errorMessage":"messages parameter is required","messagePattern":"messages parameter is required","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"litellm/proxy/anthropic_endpoints/endpoints.py","lineNumber":270,"sourceCode":"    ```\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,\n        )\n        _token_response_dict: dict = {}\n        if isinstance(token_response, TokenCountResponse):","sourceCodeStart":252,"sourceCodeEnd":288,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/anthropic_endpoints/endpoints.py#L252-L288","documentation":"Thrown by the Anthropic-compatible token counting route POST /v1/messages/count_tokens when the JSON body omits the messages field or passes an empty list. The endpoint reads data.get('messages', []), so both a missing key and [] evaluate falsy and trigger the 400. It mirrors the Anthropic Messages API contract, where messages is required exactly like on /v1/messages.","triggerScenarios":"POST /v1/messages/count_tokens with a body like {\"model\": \"claude-3-sonnet-20240229\"} and no messages key; sending \"messages\": []; sending messages under a different key name (e.g. \"message\" or nesting it inside \"params\").","commonSituations":"Porting an Anthropic SDK count_tokens call to litellm proxy and dropping the messages field during refactor; testing the endpoint with a minimal body; sending messages as a plain string instead of a list of role/content objects.","solutions":["Add a non-empty messages array: [{\"role\": \"user\", \"content\": \"Hello\"}] to the request body next to model","Verify the field is named exactly 'messages' and is a list, not a string or dict","Validate the payload with the Anthropic count_tokens schema before sending if you build requests dynamically"],"exampleFix":"// before\ncurl -X POST http://localhost:4000/v1/messages/count_tokens \\\n  -d '{\"model\": \"claude-3-5-sonnet-20241022\"}'\n\n// after\ncurl -X POST http://localhost:4000/v1/messages/count_tokens \\\n  -H \"Authorization: Bearer sk-...\" \\\n  -d '{\"model\": \"claude-3-5-sonnet-20241022\", \"messages\": [{\"role\": \"user\", \"content\": \"Hello Claude!\"}]}'","handlingStrategy":"validation","validationCode":"def valid_count_tokens_body(body: dict) -> bool:\n    return bool(body.get(\"model\")) and isinstance(body.get(\"messages\"), list) and len(body[\"messages\"]) > 0\n\nif not valid_count_tokens_body(payload):\n    raise ValueError(\"count_tokens requires 'model' and a non-empty 'messages' list\")","typeGuard":"def is_non_empty_message_list(messages: object) -> bool:\n    return isinstance(messages, list) and len(messages) > 0 and all(\n        isinstance(m, dict) and isinstance(m.get(\"role\"), str) and \"content\" in m\n        for m in messages\n    )","tryCatchPattern":"try:\n    resp = requests.post(f\"{base}/v1/messages/count_tokens\", json=payload, headers=headers)\n    resp.raise_for_status()\nexcept requests.HTTPError as e:\n    if e.response.status_code == 400 and \"messages parameter is required\" in e.response.text:\n        raise ValueError(\"payload missing messages\") from e\n    raise","preventionTips":["Build count_tokens payloads through one helper that always sets model and a non-empty messages list","Assert the Anthropic payload shape in unit tests for request builders","Remember an empty messages list [] fails the same check as a missing field"],"tags":["anthropic","count-tokens","validation","bad-request","litellm-proxy"],"backgroundTag":"missing-required-parameter","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}