BerriAI/litellm · error · ValueError

Missing required key 'url' in image_url dict.

Error message

Missing required key 'url' in image_url dict.

What it means

An image_url content block was given as a dict, so litellm expects {'url': ..., 'detail': ...}; the 'url' key is missing, empty, or None. With nothing to fetch or size, token counting aborts before doing any math.

Source

Thrown at litellm/litellm_core_utils/token_counter.py:592

    Count tokens for an image_url content block.

    Args:
        image_url: The image URL data - can be a string URL or dict with 'url' and 'detail'
        use_default_image_token_count: Whether to use default image token counts

    Returns:
        int: Number of tokens for the image

    Raises:
        ValueError: If image_url is invalid type or detail value is invalid
    """
    if isinstance(image_url, dict):
        detail: Final = image_url.get("detail", "auto")
        if detail not in ["low", "high", "auto"]:
            raise ValueError(f"Invalid detail value: {detail}. Expected 'low', 'high', or 'auto'.")
        url: Final = image_url.get("url")
        if not url:
            raise ValueError("Missing required key 'url' in image_url dict.")
        return calculate_img_tokens(
            data=url,
            mode=detail,
            use_default_image_token_count=use_default_image_token_count,
        )
    elif isinstance(image_url, str):
        if not image_url.strip():
            raise ValueError("Empty image_url string is not valid.")
        return calculate_img_tokens(
            data=image_url,
            mode="auto",
            use_default_image_token_count=use_default_image_token_count,
        )
    else:
        raise ValueError(f"Invalid image_url type: {type(image_url).__name__}. Expected str or dict with 'url' field.")


def _validate_anthropic_content(content: Mapping[str, Any]) -> type:

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Ensure every image_url dict includes a non-empty 'url' (http(s) URL or base64 data URI).
  2. Filter out image blocks without a url before calling token_counter.

Example fix

# before
msg = {"role": "user", "content": [{"type": "image_url", "image_url": {"detail": "high"}}]}

# after
msg = {"role": "user", "content": [{"type": "image_url", "image_url": {"url": data_uri, "detail": "high"}}]}
Defensive patterns

Strategy: validation

Validate before calling

content = [b for b in content
           if not (isinstance(b, dict) and b.get("type") == "image_url"
                   and not b.get("image_url", {}).get("url"))]
n = litellm.token_counter(model=m, messages=[{"content": content}])

Type guard

def has_url(image_url: dict) -> bool:
    return bool(image_url.get("url"))

Prevention

When it happens

Trigger: An image_url dict with only 'detail' and no 'url' (e.g. {"type":"image_url","image_url":{"detail":"low"}}); image_url set to {}; url explicitly None from optional access on user input.

Common situations: Building multimodal messages from partial uploads where the image field was never populated; frontends sending detail-only config blocks; dict merges that drop the url key.

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/e971d8b971b2c278. Report an issue: GitHub.