BerriAI/litellm · error · HTTPException

messages parameter is required

Error message

messages parameter is required

What it means

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.

Source

Thrown at litellm/proxy/anthropic_endpoints/endpoints.py:270

    ```
    
    Returns: {"input_tokens": <number>}
    """
    from litellm.proxy.proxy_server import token_counter as internal_token_counter

    try:
        request_data: Final = await _read_request_body(request=request)
        data: Final[dict] = {**request_data}

        # Extract required fields
        model_name: Final = data.get("model")
        messages: Final = data.get("messages", [])

        if not model_name:
            raise HTTPException(status_code=400, detail={"error": "model parameter is required"})

        if not messages:
            raise HTTPException(status_code=400, detail={"error": "messages parameter is required"})

        # Create TokenCountRequest for the internal endpoint
        from litellm.proxy._types import TokenCountRequest

        token_request: Final = TokenCountRequest(
            model=model_name,
            messages=messages,
            tools=data.get("tools"),
            system=data.get("system"),
        )

        # Call the internal token counter function with direct request flag set to False
        token_response: Final = await internal_token_counter(
            request=token_request,
            call_endpoint=True,
        )
        _token_response_dict: dict = {}
        if isinstance(token_response, TokenCountResponse):

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Add a non-empty messages array: [{"role": "user", "content": "Hello"}] to the request body next to model
  2. Verify the field is named exactly 'messages' and is a list, not a string or dict
  3. Validate the payload with the Anthropic count_tokens schema before sending if you build requests dynamically

Example fix

// before
curl -X POST http://localhost:4000/v1/messages/count_tokens \
  -d '{"model": "claude-3-5-sonnet-20241022"}'

// after
curl -X POST http://localhost:4000/v1/messages/count_tokens \
  -H "Authorization: Bearer sk-..." \
  -d '{"model": "claude-3-5-sonnet-20241022", "messages": [{"role": "user", "content": "Hello Claude!"}]}'
Defensive patterns

Strategy: validation

Validate before calling

def valid_count_tokens_body(body: dict) -> bool:
    return bool(body.get("model")) and isinstance(body.get("messages"), list) and len(body["messages"]) > 0

if not valid_count_tokens_body(payload):
    raise ValueError("count_tokens requires 'model' and a non-empty 'messages' list")

Type guard

def is_non_empty_message_list(messages: object) -> bool:
    return isinstance(messages, list) and len(messages) > 0 and all(
        isinstance(m, dict) and isinstance(m.get("role"), str) and "content" in m
        for m in messages
    )

Try / catch

try:
    resp = requests.post(f"{base}/v1/messages/count_tokens", json=payload, headers=headers)
    resp.raise_for_status()
except requests.HTTPError as e:
    if e.response.status_code == 400 and "messages parameter is required" in e.response.text:
        raise ValueError("payload missing messages") from e
    raise

Prevention

When it happens

Trigger: 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").

Common situations: 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.

Understand the failure class

Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.

Related errors


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/8658ba8bf56cb3e9. Report an issue: GitHub.