BerriAI/litellm · error · HTTPException

model parameter is required

Error message

model parameter is required

What it means

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.

Source

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

        "model": "claude-3-sonnet-20240229",
        "messages": [{"role": "user", "content": "Hello Claude!"}]
      }'
    ```
    
    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,

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. 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.
  2. Verify Content-Type: application/json and that the body is not empty/malformed before it reaches the proxy.
  3. If you were using the LiteLLM-internal shape, switch to the Anthropic Messages shape (model/messages/system/tools) that this endpoint mirrors.
  4. Check any middleware that rewrites the body and confirm it preserves the model key.

Example fix

# before
curl -X POST http://localhost:4000/v1/messages/count_tokens \
  -H "Authorization: Bearer sk-..." -H "Content-Type: application/json" \
  -d '{"messages": [{"role": "user", "content": "Hello"}]}'
# -> 400 model parameter is required

# after
curl -X POST http://localhost:4000/v1/messages/count_tokens \
  -H "Authorization: Bearer sk-..." -H "Content-Type: application/json" \
  -d '{"model": "claude-3-sonnet-20240229", "messages": [{"role": "user", "content": "Hello"}]}'
Defensive patterns

Strategy: validation

Validate before calling

body = {"model": model, "messages": messages}
if not body.get("model"):
    raise ValueError("count_tokens requires a non-empty 'model'")
if not body.get("messages"):
    raise ValueError("count_tokens requires non-empty 'messages'")
resp = client.post(f"{base}/v1/messages/count_tokens", json=body, headers=hdr)

Type guard

interface CountTokensBody {
  model: string;
  messages: Array<{ role: string; content: unknown }>;
}
function isCountTokensBody(b: unknown): b is CountTokensBody {
  const o = b as Record<string, unknown>;
  return typeof o?.model === 'string' && o.model.length > 0 && Array.isArray(o?.messages) && o.messages.length > 0;
}

Try / catch

try:
    resp = client.post(f"{base}/v1/messages/count_tokens", json=body, headers=hdr)
    resp.raise_for_status()
except httpx.HTTPStatusError as e:
    if e.response.status_code == 400 and "model parameter is required" in e.response.text:
        raise ValueError("count_tokens body needs 'model' (and 'messages')") from e
    raise

Prevention

When it happens

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

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

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/71eb5635558b9df2. Report an issue: GitHub.