BerriAI/litellm · error · Exception

Image url not in expected format. Example Expected input - "

Error message

Image url not in expected format. Example Expected input - "image_url": "data:image/jpeg;base64,{base64_image}". 

What it means

Raised in convert_url_to_base64: LiteLLM tried to normalize an image_url into base64 data and every path failed. The URL was not a fetchable http(s) image (fetch errors are re-raised as-is) and the string did not contain the expected 'data:image/...;base64,' structure, so the fallback parse threw and this generic Exception wraps it. The message shows the expected data-URI form.

Source

Thrown at litellm/litellm_core_utils/prompt_templates/factory.py:183

    return prompt


def convert_to_ollama_image(openai_image_url: str):
    try:
        if openai_image_url.startswith("http"):
            openai_image_url = convert_url_to_base64(url=openai_image_url)

        if openai_image_url.startswith("data:image/"):
            # Extract the base64 image data
            base64_data = openai_image_url.split("data:image/")[1].split(";base64,")[1]
        else:
            base64_data = openai_image_url

        return base64_data
    except Exception as e:
        if "Error: Unable to fetch image from URL" in str(e):
            raise e
        raise Exception(
            """Image url not in expected format. Example Expected input - "image_url": "data:image/jpeg;base64,{base64_image}". """
        )


def _handle_ollama_system_message(messages: list, prompt: str, msg_i: int) -> tuple[str, int]:
    system_content_str = ""
    ## MERGE CONSECUTIVE SYSTEM CONTENT ##
    while msg_i < len(messages) and messages[msg_i]["role"] == "system":
        msg_content = convert_content_list_to_str(messages[msg_i])
        system_content_str += msg_content

        msg_i += 1

    return system_content_str, msg_i


def ollama_pt(
    model: str, messages: list

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Use a proper data URI: "data:image/jpeg;base64,<base64_data>"
  2. If using an http(s) URL, verify it returns 200 with an image content-type (curl -I) and is reachable from where LiteLLM runs
  3. For local files, base64-encode them yourself into a data URI instead of passing a path
  4. For cloud-store images, download the bytes first (boto3/gcs client) then inline them as base64

Example fix

# before
msg = {"role": "user", "content": [
    {"type": "image_url", "image_url": {"url": "/tmp/cat.png"}}
]}

# after
import base64, mimetypes
path = "/tmp/cat.png"
b64 = base64.b64encode(open(path, "rb").read()).decode()
mime = mimetypes.guess_type(path)[0] or "image/png"
msg = {"role": "user", "content": [
    {"type": "image_url", "image_url": {"url": f"data:{mime};base64,{b64}"}}
]}
Defensive patterns

Strategy: validation

Validate before calling

import re

DATA_URI_RE = re.compile(r"^data:image/(?:jpeg|png|gif|webp);base64,[A-Za-z0-9+/=\s]+$")

def is_usable_image_url(u: str) -> bool:
    return u.startswith(("http://", "https://")) or bool(DATA_URI_RE.match(u))

for block in content:
    if block.get("type") == "image_url" and not is_usable_image_url(block["image_url"]["url"]):
        raise ValueError(f"bad image_url: {block['image_url']['url'][:50]}...")

Type guard

import re
from typing import Any

_DATA_URI = re.compile(r"^data:image/(?:jpeg|png|gif|webp);base64,[A-Za-z0-9+/=]+$")

def is_valid_image_url(v: Any) -> bool:
    return isinstance(v, str) and (v.startswith(("http://", "https://")) or bool(_DATA_URI.match(v)))

Try / catch

try:
    litellm.completion(model=model, messages=messages)
except Exception as e:
    if "Image url not in expected format" in str(e):
        # re-encode the image locally as a data URI and retry once
        b64 = base64.b64encode(fetch(image_path).content).decode()
        messages = inject_data_uri(messages, f"data:image/png;base64,{b64}")
        litellm.completion(model=model, messages=messages)
    else:
        raise

Prevention

When it happens

Trigger: Passing a vision message where image_url.url is a relative path, an S3/gs:// URI, a data URI missing ';base64,' or with a malformed prefix (e.g. 'data:image/jpeg, ...'), or a URL that returns HTML/non-image bytes; occurs on models whose handler converts images server-side (Ollama, Anthropic, Bedrock image paths).

Common situations: Using presigned S3/GCS URLs that expired or redirect to a login page; hand-building data URIs with typos; local file paths ('/tmp/img.png') instead of http URLs or base64 data URIs; providers that cannot fetch intranet URLs from LiteLLM's host.

Related errors


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