BerriAI/litellm · error · ValueError
Invalid image URL: {content_image_url}
Error message
Invalid image URL: {content_image_url} What it means
_convert_image_url raises when an image content part yields no usable URL: the part is a dict whose 'url' key is missing or None (a bare string is accepted as-is). This happens while converting chat content blocks to Responses API input_image items.
Source
Thrown at litellm/completion_extras/litellm_responses_transformation/transformation.py:832
self, content: "ChatCompletionImageObject", role: str
) -> "ResponseInputImageParam":
from openai.types.responses import ResponseInputImageParam
content_image_url: Final = content.get("image_url")
actual_image_url: str | None = None
detail: Literal["low", "high", "auto"] | None = None
if isinstance(content_image_url, str):
actual_image_url = content_image_url
elif isinstance(content_image_url, dict):
actual_image_url = content_image_url.get("url")
detail = cast(
Literal["low", "high", "auto"] | None,
content_image_url.get("detail"),
)
if actual_image_url is None:
raise ValueError(f"Invalid image URL: {content_image_url}")
image_param: Final = ResponseInputImageParam(image_url=actual_image_url, detail="auto", type="input_image")
if detail:
image_param["detail"] = detail
return image_param
def _convert_content_to_responses_format(
self,
content: str
| list[object]
| Iterable[
Union["OpenAIMessageContentListBlock", "ChatCompletionThinkingBlock", "ChatCompletionRedactedThinkingBlock"]
]
| None,
role: str,
) -> list[dict[str, object]]:View on GitHub (pinned to 6c2dcb801b)
Solutions
- Ensure every image part has image_url.url set to an http(s) URL or a data: URL
- Validate dynamic image parts before sending: skip or fail fast when the URL source returns None
- Check for key typos ('src', 'imageUrl') when mapping from your own attachment model
Example fix
# before
content = [
{"type": "text", "text": "what is this?"},
{"type": "image_url", "image_url": {"detail": "high"}}, # no url
]
# after
content = [
{"type": "text", "text": "what is this?"},
{"type": "image_url", "image_url": {"url": image_src, "detail": "high"}},
] Defensive patterns
Strategy: validation
Validate before calling
def image_parts_valid(content) -> bool:
if isinstance(content, str):
return True
for part in content or []:
if isinstance(part, dict) and part.get("type") == "image_url":
url = (part.get("image_url") or {}).get("url")
if not url:
return False
return True Type guard
def has_valid_image_url(part: dict) -> bool:
iu = part.get("image_url")
return (isinstance(iu, str) and iu) or (isinstance(iu, dict) and isinstance(iu.get("url"), str) and bool(iu["url"])) Prevention
- Validate image parts at your input boundary before calling litellm
- Fail fast when an upstream URL fetch returns None instead of building the part
- Use data: URLs for local images; verify the key is exactly 'url'
When it happens
Trigger: Sending content: [{'type': 'image_url', 'image_url': {}}] or {'image_url': {'detail': 'high'}} with no url; None url; base64 payloads built incorrectly so the url key is dropped.
Common situations: Dynamically assembling image parts where the URL fetch failed upstream; typos like 'imageUrl' or 'src' instead of 'url'; data-URL builders returning None on error.
Related errors
- Image url not in expected format. Example Expected input - "
- Unsupported image format: {image_format}. Supported formats:
- Invalid mode: {custom_auth_settings['mode']}
- Filtering by 'provider' is not supported when using managed
- Filtering by 'target_model_names' is not supported when usin
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/42717e927be0f77d.
Report an issue: GitHub.