langchain-ai/langchain · error · ValueError
Unrecognized content block at messages[{i}].content[{j}] has
Error message
Unrecognized content block at messages[{i}].content[{j}] has 'type': 'image' but does not have a 'source' or 'image' key. Full content block:
{block} What it means
`convert_to_openai_messages` hits this branch when a block declares `"type": "image"` but has neither an Anthropic-style `source` key nor a Bedrock-style `image` key. The converter recognizes two image dialects: Anthropic (`{"type": "image", "source": {...}}`) and Bedrock Converse (`{"type": "image", "image": {...}}`). With neither present it cannot locate the image payload, so it raises rather than emit a broken `image_url` block.
Source
Thrown at libs/core/langchain_core/messages/utils.py:1780
b64_image = _bytes_to_b64_str(image["source"]["bytes"])
content.append(
{
"type": "image_url",
"image_url": {
"url": (
f"data:image/{image['format']};base64,{b64_image}"
)
},
}
)
else:
err = (
f"Unrecognized content block at "
f"messages[{i}].content[{j}] has 'type': 'image' "
f"but does not have a 'source' or 'image' key. Full "
f"content block:\n\n{block}"
)
raise ValueError(err)
# OpenAI file format
elif (
block.get("type") == "file"
and isinstance(block.get("file"), dict)
and isinstance(block.get("file", {}).get("file_data"), str)
):
if block.get("file", {}).get("filename") is None:
logger.info("Generating a fallback filename.")
formatted_block = {
**block,
"file": {**block["file"], "filename": "LC_AUTOGENERATED"},
}
content.append(formatted_block)
else:
content.append(block)
# OpenAI audio format
elif (
block.get("type") == "input_audio"View on GitHub (pinned to e32fa9a52e)
Solutions
- Use the OpenAI shape: `{"type": "image_url", "image_url": {"url": "..."}}` — do not set `type` to `image`.
- Or use Anthropic shape: `{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": "<b64>"}}`.
- Or use Bedrock shape: `{"type": "image", "image": {"format": ..., "source": {"bytes": ...}}}`.
- Search your message-construction code for `"type": "image"` and replace with one of the three canonical shapes above.
Example fix
// before
{"type": "image", "url": "https://example.com/cat.png"}
// after
{"type": "image_url", "image_url": {"url": "https://example.com/cat.png"}} Defensive patterns
Strategy: validation
Validate before calling
def is_recognized_image_block(b: dict) -> bool:
if b.get("type") != "image":
return True
return "source" in b or isinstance(b.get("image"), dict)
blocks = [b for b in blocks if is_recognized_image_block(b)] # or raise early with your own message Type guard
def is_anthropic_image(b: dict) -> bool:
return (
b.get("type") == "image"
and isinstance(b.get("source"), dict)
and b["source"].get("type") in {"base64", "url"}
) Try / catch
try:
oai = convert_to_openai_messages(messages)
except ValueError as e:
# error includes the full offending block; log and reject the input payload
raise HTTPException(400, "unsupported image block") if serving else None Prevention
- Standardize on one image dialect (prefer OpenAI image_url) across your codebase
- Ban hand-written 'type': 'image' dicts; use a builder function
- Add schema tests for message content before it reaches providers
When it happens
Trigger: Blocks like `{"type": "image", "url": "https://..."}` or `{"type": "image", "data": "<b64>"}` — keys the converter does not look for when `type == "image"`. Also image blocks whose payload key was renamed or nested differently by upstream code.
Common situations: Developers assuming OpenAI-style `image_url` goes under `type: "image"`; LLM-generated or user-submitted content blocks with ad-hoc schemas; migrating from frameworks that use `url`/`data` keys for images.
Related errors
- Unsupported source type. Only 'url' and 'base64' are support
- Keys base64, url, or file_id required for file blocks.
- Block of type {block['type']} is not supported.
- Unrecognized content block at messages[{i}].content[{j}] has
- Unrecognized content block at messages[{i}].content[{j}] has
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/09798227a057eef9.
Report an issue: GitHub.