{"record":{"id":"6d9d6debaea54423","repo":"BerriAI/litellm","slug":"image-url-not-in-expected-format-example-expected","errorCode":null,"errorMessage":"Image url not in expected format. Example Expected input - \"image_url\": \"data:image/jpeg;base64,{base64_image}\". ","messagePattern":"Image url not in expected format\\. Example Expected input - \"image_url\": \"data:image/jpeg;base64,(.+?)\"\\. ","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"litellm/litellm_core_utils/prompt_templates/factory.py","lineNumber":183,"sourceCode":"    return prompt\n\n\ndef convert_to_ollama_image(openai_image_url: str):\n    try:\n        if openai_image_url.startswith(\"http\"):\n            openai_image_url = convert_url_to_base64(url=openai_image_url)\n\n        if openai_image_url.startswith(\"data:image/\"):\n            # Extract the base64 image data\n            base64_data = openai_image_url.split(\"data:image/\")[1].split(\";base64,\")[1]\n        else:\n            base64_data = openai_image_url\n\n        return base64_data\n    except Exception as e:\n        if \"Error: Unable to fetch image from URL\" in str(e):\n            raise e\n        raise Exception(\n            \"\"\"Image url not in expected format. Example Expected input - \"image_url\": \"data:image/jpeg;base64,{base64_image}\". \"\"\"\n        )\n\n\ndef _handle_ollama_system_message(messages: list, prompt: str, msg_i: int) -> tuple[str, int]:\n    system_content_str = \"\"\n    ## MERGE CONSECUTIVE SYSTEM CONTENT ##\n    while msg_i < len(messages) and messages[msg_i][\"role\"] == \"system\":\n        msg_content = convert_content_list_to_str(messages[msg_i])\n        system_content_str += msg_content\n\n        msg_i += 1\n\n    return system_content_str, msg_i\n\n\ndef ollama_pt(\n    model: str, messages: list","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/litellm_core_utils/prompt_templates/factory.py#L165-L201","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Use a proper data URI: \"data:image/jpeg;base64,<base64_data>\"","If using an http(s) URL, verify it returns 200 with an image content-type (curl -I) and is reachable from where LiteLLM runs","For local files, base64-encode them yourself into a data URI instead of passing a path","For cloud-store images, download the bytes first (boto3/gcs client) then inline them as base64"],"exampleFix":"# before\nmsg = {\"role\": \"user\", \"content\": [\n    {\"type\": \"image_url\", \"image_url\": {\"url\": \"/tmp/cat.png\"}}\n]}\n\n# after\nimport base64, mimetypes\npath = \"/tmp/cat.png\"\nb64 = base64.b64encode(open(path, \"rb\").read()).decode()\nmime = mimetypes.guess_type(path)[0] or \"image/png\"\nmsg = {\"role\": \"user\", \"content\": [\n    {\"type\": \"image_url\", \"image_url\": {\"url\": f\"data:{mime};base64,{b64}\"}}\n]}","handlingStrategy":"validation","validationCode":"import re\n\nDATA_URI_RE = re.compile(r\"^data:image/(?:jpeg|png|gif|webp);base64,[A-Za-z0-9+/=\\s]+$\")\n\ndef is_usable_image_url(u: str) -> bool:\n    return u.startswith((\"http://\", \"https://\")) or bool(DATA_URI_RE.match(u))\n\nfor block in content:\n    if block.get(\"type\") == \"image_url\" and not is_usable_image_url(block[\"image_url\"][\"url\"]):\n        raise ValueError(f\"bad image_url: {block['image_url']['url'][:50]}...\")","typeGuard":"import re\nfrom typing import Any\n\n_DATA_URI = re.compile(r\"^data:image/(?:jpeg|png|gif|webp);base64,[A-Za-z0-9+/=]+$\")\n\ndef is_valid_image_url(v: Any) -> bool:\n    return isinstance(v, str) and (v.startswith((\"http://\", \"https://\")) or bool(_DATA_URI.match(v)))","tryCatchPattern":"try:\n    litellm.completion(model=model, messages=messages)\nexcept Exception as e:\n    if \"Image url not in expected format\" in str(e):\n        # re-encode the image locally as a data URI and retry once\n        b64 = base64.b64encode(fetch(image_path).content).decode()\n        messages = inject_data_uri(messages, f\"data:image/png;base64,{b64}\")\n        litellm.completion(model=model, messages=messages)\n    else:\n        raise","preventionTips":["Always send images as data URIs you generated yourself or verified http(s) URLs","curl -I any image URL once before shipping to confirm image/* content-type","Base64-encode local files; never pass filesystem paths"],"tags":["vision","image","base64","input"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}