{"record":{"id":"42717e927be0f77d","repo":"BerriAI/litellm","slug":"invalid-image-url-content-image-url","errorCode":null,"errorMessage":"Invalid image URL: {content_image_url}","messagePattern":"Invalid image URL: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/completion_extras/litellm_responses_transformation/transformation.py","lineNumber":834,"sourceCode":"        self, content: \"ChatCompletionImageObject\", role: str\n    ) -> \"ResponseInputImageParam\":\n        from openai.types.responses import ResponseInputImageParam\n\n        content_image_url: Final = content.get(\"image_url\")\n        actual_image_url: str | None = None\n        detail: Literal[\"low\", \"high\", \"auto\"] | None = None\n\n        if isinstance(content_image_url, str):\n            actual_image_url = content_image_url\n        elif isinstance(content_image_url, dict):\n            actual_image_url = content_image_url.get(\"url\")\n            detail = cast(\n                Literal[\"low\", \"high\", \"auto\"] | None,\n                content_image_url.get(\"detail\"),\n            )\n\n        if actual_image_url is None:\n            raise ValueError(f\"Invalid image URL: {content_image_url}\")\n\n        image_param: Final = ResponseInputImageParam(image_url=actual_image_url, detail=\"auto\", type=\"input_image\")\n\n        if detail:\n            image_param[\"detail\"] = detail\n\n        return image_param\n\n    def _convert_content_to_responses_format(\n        self,\n        content: str\n        | list[object]\n        | Iterable[\n            Union[\"OpenAIMessageContentListBlock\", \"ChatCompletionThinkingBlock\", \"ChatCompletionRedactedThinkingBlock\"]\n        ]\n        | None,\n        role: str,\n    ) -> list[dict[str, object]]:","sourceCodeStart":816,"sourceCodeEnd":852,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/completion_extras/litellm_responses_transformation/transformation.py#L816-L852","documentation":"While converting multimodal chat content to Responses API input, an image_url content block yielded no usable URL: image_url was neither a plain string nor a dict containing a 'url' key (or the url value was None). The Responses API requires input_image.image_url to be an actual URL string, so the bridge rejects the block up front with the offending value echoed in the message.","triggerScenarios":"messages with {\"type\":\"image_url\",\"image_url\":{}} (empty object); image_url key missing or None; url misspelled or nested one level wrong (e.g. passing {\"image_url\": {\"image_url\": {...}}}); image blocks produced by another SDK's schema and forwarded unconverted; content where the URL failed to serialize.","commonSituations":"Multimodal agent loops replaying stored conversations where the URL field was dropped; converting Anthropic-style image blocks (source/base64) to OpenAI format incompletely; frontend forms submitting empty image fields; base64 data URLs built with a typo in the key.","solutions":["Ensure every image block is {\"type\":\"image_url\",\"image_url\":{\"url\":\"https://...\" or \"data:image/png;base64,...\"}}","Validate image blocks in a preflight loop and drop or reject blocks without a non-empty url string","When converting from other formats, map the source's URL/base64 field into the url key explicitly","Add optional detail only as image_url.detail — never in place of url"],"exampleFix":"// before\nmessages=[{\"role\":\"user\",\"content\":[\n  {\"type\": \"image_url\", \"image_url\": {}},  # ValueError: Invalid image URL: {}\n  {\"type\": \"text\", \"text\": \"what is this?\"}]}]\n\n// after\nmessages=[{\"role\":\"user\",\"content\":[\n  {\"type\": \"image_url\", \"image_url\": {\"url\": \"https://example.com/cat.png\", \"detail\": \"auto\"}},\n  {\"type\": \"text\", \"text\": \"what is this?\"}]}]","handlingStrategy":"validation","validationCode":"def image_blocks_are_valid(messages) -> bool:\n    for msg in messages or []:\n        content = msg.get(\"content\")\n        if not isinstance(content, list):\n            continue\n        for block in content:\n            if isinstance(block, dict) and block.get(\"type\") == \"image_url\":\n                iu = block.get(\"image_url\")\n                url = iu if isinstance(iu, str) else (iu or {}).get(\"url\") if isinstance(iu, dict) else None\n                if not isinstance(url, str) or not url:\n                    return False\n    return True","typeGuard":"def is_valid_image_block(block: dict) -> bool:\n    iu = block.get(\"image_url\")\n    return isinstance(iu, str) or (isinstance(iu, dict) and isinstance(iu.get(\"url\"), str) and bool(iu[\"url\"]))","tryCatchPattern":"try:\n    resp = litellm.completion(model=m, messages=messages)\nexcept ValueError as e:\n    if \"Invalid image URL\" in str(e):\n        cleaned = [sanitize_image_blocks(msg) for msg in messages]  # drop/repair bad blocks\n        resp = litellm.completion(model=m, messages=cleaned)\n    else:\n        raise","preventionTips":["Preflight multimodal messages: every image_url block needs a non-empty url (https:// or data:image/...;base64,)","Map foreign image schemas (Anthropic source blocks) explicitly onto image_url.url","Reject empty image uploads at the API edge before they enter stored conversation history"],"tags":["multimodal","image-url","messages","validation"],"backgroundTag":"invalid-image-url","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}