BerriAI/litellm · error · Exception

Error: Unsupported image format. Format={_img_type}. Support

Error message

Error: Unsupported image format. Format={_img_type}. Supported types = ['image/jpeg', 'image/png', 'image/gif', 'image/webp']

What it means

Raised in convert_url_to_base64 when the image HTTP response has no Content-Type header and the URL's file extension is not one of jpg/jpeg/png/gif/webp. The extension is mapped to a MIME type via a fixed dict; unknown or missing extensions raise. Note the message has a formatting bug: it interpolates _img_type which is always None at that point.

Source

Thrown at litellm/litellm_core_utils/prompt_templates/image_handling.py:63

            raise litellm.ImageFetchError(
                f"Error: Image size ({size_mb:.2f}MB) exceeds maximum allowed size ({MAX_IMAGE_URL_DOWNLOAD_SIZE_MB}MB). url={url}"
            )
        image_bytes.extend(chunk)

    base64_image: Final = base64.b64encode(image_bytes).decode("utf-8")

    image_type: Final = response.headers.get("Content-Type")
    if image_type is None:
        img_type = url.split(".")[-1].lower()
        _img_type: Final = {
            "jpg": "image/jpeg",
            "jpeg": "image/jpeg",
            "png": "image/png",
            "gif": "image/gif",
            "webp": "image/webp",
        }.get(img_type)
        if _img_type is None:
            raise Exception(
                f"Error: Unsupported image format. Format={_img_type}. Supported types = ['image/jpeg', 'image/png', 'image/gif', 'image/webp']"
            )
        img_type = _img_type
    else:
        img_type = image_type

    result: Final = f"data:{img_type};base64,{base64_image}"
    in_memory_cache.set_cache(url, result)
    return result


async def async_convert_url_to_base64(url: str) -> str:
    if url.startswith("data:") and ";base64," in url:
        return url

    # If MAX_IMAGE_URL_DOWNLOAD_SIZE_MB is 0, block all image downloads
    if MAX_IMAGE_URL_DOWNLOAD_SIZE_MB == 0:
        raise litellm.ImageFetchError(

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Use an image host that returns a proper Content-Type header — the fallback map is then skipped.
  2. Serve the image from an extension-bearing URL (.png/.jpg/.jpeg/.gif/.webp) without a query suffix.
  3. Convert unsupported formats (svg/avif/bmp) to png/jpeg before passing the URL.
  4. Alternatively download and pass the image as a base64 data URI to bypass URL sniffing.

Example fix

# before
{"type": "image_url", "image_url": {"url": "https://cdn.example.com/avatar?size=512"}}
# after
{"type": "image_url", "image_url": {"url": "https://cdn.example.com/avatar.png"}}
Defensive patterns

Strategy: validation

Validate before calling

SUPPORTED = {"jpg", "jpeg", "png", "gif", "webp"}

def image_url_is_safe(url: str) -> bool:
    path = urlparse(url).path
    ext = path.rsplit(".", 1)[-1].lower() if "." in path else ""
    return ext in SUPPORTED or url.startswith("data:image/")

Type guard

def is_probably_supported_image(url: str) -> bool:
    if url.startswith("data:"):
        return True
    ext = urlparse(url).path.rsplit(".", 1)[-1].lower()
    return ext in {"jpg", "jpeg", "png", "gif", "webp"}

Try / catch

try:
    resp = litellm.completion(model=..., messages=msgs)
except Exception as e:
    if "Unsupported image format" in str(e):
        msgs = inline_image_as_data_uri(msgs)  # download + base64 locally
        resp = litellm.completion(model=..., messages=msgs)

Prevention

When it happens

Trigger: Fetching an image URL like https://host/img.svg, .avif, .bmp, a CDN URL with no extension, or an extension hidden behind a query string (?w=800), when the server also omits Content-Type.

Common situations: Signed CDN URLs (extension-less or with query params); WebP/AVIF variants the map doesn't cover; presigned S3 URLs stripped of extension; SVG images which are unsupported regardless.

Related errors


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