BerriAI/litellm · error · ValueError

Unable to determine content type from URL: {url}. Response c

Error message

Unable to determine content type from URL: {url}. Response content-type: {current_content_type}

What it means

When litellm downloads an image from a URL (for vision inputs), it tries several strategies to determine the content type: the HTTP response's Content-Type header, magic-byte sniffing of the downloaded bytes (png/jpeg/gif/webp/heic detection), and filename hints. If all fallbacks fail — the header is generic/missing and the bytes don't match a known image signature — it raises ValueError with the URL and the header value it saw.

Source

Thrown at litellm/litellm_core_utils/prompt_templates/common_utils.py:1233

        if inferred_type:
            return inferred_type

    # Try to detect from binary content signature (magic bytes)
    if content:
        detected_type: Final = get_image_type(content[:100])
        if detected_type:
            type_to_mime: Final = {
                "png": "image/png",
                "jpeg": "image/jpeg",
                "gif": "image/gif",
                "webp": "image/webp",
                "heic": "image/heic",
            }
            if detected_type in type_to_mime:
                return type_to_mime[detected_type]

    # If all fallbacks failed, raise error
    raise ValueError(f"Unable to determine content type from URL: {url}. Response content-type: {current_content_type}")


def get_tool_call_names(tools: list[ChatCompletionToolParam]) -> list[str]:
    """
    Get tool call names from tools
    """
    tool_call_names: Final[list[str]] = []
    for tool in tools:
        if tool.get("type") == "function":
            tool_call_name = tool.get("function", {}).get("name")
            if tool_call_name:
                tool_call_names.append(tool_call_name)
    return tool_call_names


def is_function_call(optional_params: dict) -> bool:
    """
    Checks if the optional params contain the function call

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Verify the URL actually returns image bytes: curl -I <url> and check Content-Type; open it in a browser.
  2. Convert the image to PNG/JPEG and re-host it where the server sets a correct Content-Type.
  3. For SVGs, rasterize to PNG first — most vision models don't accept SVG anyway.
  4. Refresh expired signed URLs; ensure auth cookies/headers aren't required for the fetch.
  5. If the format is supported but the server header is wrong, embed the image as base64 data URL with an explicit mime type.

Example fix

// before
{'type':'image_url','image_url':{'url':'https://cdn.example.com/chart.svg'}}

# after (rasterize + embed base64)
import base64
png_b64 = base64.b64encode(open('chart.png','rb').read()).decode()
{'type':'image_url','image_url':{'url':f'data:image/png;base64,{png_b64}'}}
Defensive patterns

Strategy: validation

Validate before calling

import urllib.request

def url_serves_image(url: str) -> bool:
    req = urllib.request.Request(url, method='GET', headers={'Range': 'bytes=0-15'})
    with urllib.request.urlopen(req, timeout=10) as r:
        ctype = r.headers.get('Content-Type', '')
        magic = r.read(16)
    if ctype.startswith('image/') and 'svg' not in ctype:
        return True
    return magic[:8] in (b'\x89PNG\r\n\x1a\n', b'\xff\xd8\xff') or magic[:4] == b'RIFF'

Try / catch

try:
    resp = litellm.completion(model=m, messages=[{'role':'user','content':[{'type':'image_url','image_url':{'url':u}},'describe this']}])
except ValueError as e:
    if 'Unable to determine content type' in str(e):
        u = to_base64_data_url(u)  # download, convert to PNG, embed as data URL
        resp = litellm.completion(model=m, messages=[{'role':'user','content':[{'type':'image_url','image_url':{'url':u}},'describe this']}])
    else:
        raise

Prevention

When it happens

Trigger: Passing image_url pointing to non-image content (HTML error page, SVG without a sniffable signature, login-redirect page); servers returning 'application/octet-stream' or 'text/html' with unrecognized bytes; exotic image formats not in the png/jpeg/gif/webp/heic sniff table.

Common situations: Expired/signed S3 or CDN URLs that redirect to an HTML login page; SVGs (content-type image/svg+xml but no magic bytes match in the table); WebP variants or AVIF images unsupported by the sniffer; misconfigured static servers omitting Content-Type.

Related errors


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