{"record":{"id":"09798227a057eef9","repo":"langchain-ai/langchain","slug":"unrecognized-content-block-at-messages-i-conten-097982","errorCode":null,"errorMessage":"Unrecognized content block at messages[{i}].content[{j}] has 'type': 'image' but does not have a 'source' or 'image' key. Full content block:\n\n{block}","messagePattern":"Unrecognized content block at messages\\[(.+?)\\]\\.content\\[(.+?)\\] has 'type': 'image' but does not have a 'source' or 'image' key\\. Full content block:\n\n(.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/messages/utils.py","lineNumber":1780,"sourceCode":"                        b64_image = _bytes_to_b64_str(image[\"source\"][\"bytes\"])\n                        content.append(\n                            {\n                                \"type\": \"image_url\",\n                                \"image_url\": {\n                                    \"url\": (\n                                        f\"data:image/{image['format']};base64,{b64_image}\"\n                                    )\n                                },\n                            }\n                        )\n                    else:\n                        err = (\n                            f\"Unrecognized content block at \"\n                            f\"messages[{i}].content[{j}] has 'type': 'image' \"\n                            f\"but does not have a 'source' or 'image' key. Full \"\n                            f\"content block:\\n\\n{block}\"\n                        )\n                        raise ValueError(err)\n                # OpenAI file format\n                elif (\n                    block.get(\"type\") == \"file\"\n                    and isinstance(block.get(\"file\"), dict)\n                    and isinstance(block.get(\"file\", {}).get(\"file_data\"), str)\n                ):\n                    if block.get(\"file\", {}).get(\"filename\") is None:\n                        logger.info(\"Generating a fallback filename.\")\n                        formatted_block = {\n                            **block,\n                            \"file\": {**block[\"file\"], \"filename\": \"LC_AUTOGENERATED\"},\n                        }\n                        content.append(formatted_block)\n                    else:\n                        content.append(block)\n                # OpenAI audio format\n                elif (\n                    block.get(\"type\") == \"input_audio\"","sourceCodeStart":1762,"sourceCodeEnd":1798,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/messages/utils.py#L1762-L1798","documentation":"`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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n{\"type\": \"image\", \"url\": \"https://example.com/cat.png\"}\n\n// after\n{\"type\": \"image_url\", \"image_url\": {\"url\": \"https://example.com/cat.png\"}}","handlingStrategy":"validation","validationCode":"def is_recognized_image_block(b: dict) -> bool:\n    if b.get(\"type\") != \"image\":\n        return True\n    return \"source\" in b or isinstance(b.get(\"image\"), dict)\n\nblocks = [b for b in blocks if is_recognized_image_block(b)]  # or raise early with your own message","typeGuard":"def is_anthropic_image(b: dict) -> bool:\n    return (\n        b.get(\"type\") == \"image\"\n        and isinstance(b.get(\"source\"), dict)\n        and b[\"source\"].get(\"type\") in {\"base64\", \"url\"}\n    )","tryCatchPattern":"try:\n    oai = convert_to_openai_messages(messages)\nexcept ValueError as e:\n    # error includes the full offending block; log and reject the input payload\n    raise HTTPException(400, \"unsupported image block\") if serving else None","preventionTips":["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"],"tags":["messages","content-blocks","openai","anthropic","validation"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}