{"record":{"id":"89fb1ec25bc4701b","repo":"langchain-ai/langchain","slug":"unrecognized-content-block-at-messages-i-conten-89fb1e","errorCode":null,"errorMessage":"Unrecognized content block at messages[{i}].content[{j}] has 'type': 'media' but does not have key(s) {missing}. Full content block:\n\n{block}","messagePattern":"Unrecognized content block at messages\\[(.+?)\\]\\.content\\[(.+?)\\] has 'type': 'media' but does not have key\\(s\\) (.+?)\\. Full content block:\n\n(.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/messages/utils.py","lineNumber":1925,"sourceCode":"                            f\"'guard_content' but does not have a \"\n                            f\"messages[{i}].content[{j}]['guard_content']['text'] \"\n                            f\"key. Full content block:\\n\\n{block}\"\n                        )\n                        raise ValueError(msg)\n                    text = block[\"guard_content\"][\"text\"]\n                    if isinstance(text, dict):\n                        text = text[\"text\"]\n                    content.append({\"type\": \"text\", \"text\": text})\n                # VertexAI format\n                elif block.get(\"type\") == \"media\":\n                    if missing := [k for k in (\"mime_type\", \"data\") if k not in block]:\n                        err = (\n                            f\"Unrecognized content block at \"\n                            f\"messages[{i}].content[{j}] has 'type': \"\n                            f\"'media' but does not have key(s) {missing}. Full \"\n                            f\"content block:\\n\\n{block}\"\n                        )\n                        raise ValueError(err)\n                    if \"image\" not in block[\"mime_type\"]:\n                        err = (\n                            f\"OpenAI messages can only support text and image data.\"\n                            f\" Received content block with media of type:\"\n                            f\" {block['mime_type']}\"\n                        )\n                        raise ValueError(err)\n                    b64_image = _bytes_to_b64_str(block[\"data\"])\n                    content.append(\n                        {\n                            \"type\": \"image_url\",\n                            \"image_url\": {\n                                \"url\": (f\"data:{block['mime_type']};base64,{b64_image}\")\n                            },\n                        }\n                    )\n                elif (\n                    block.get(\"type\") in {\"thinking\", \"reasoning\"}","sourceCodeStart":1907,"sourceCodeEnd":1943,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/messages/utils.py#L1907-L1943","documentation":"VertexAI-format media blocks (`{\"type\": \"media\", ...}`) must include `mime_type` and `data`; the converter base64-encodes `data` and embeds it in a data-URI using `mime_type`. If either key is absent the message lists exactly which are missing (`missing` in the error text) and aborts `convert_to_openai_messages`.","triggerScenarios":"`{\"type\": \"media\", \"mime_type\": \"image/png\"}` without `data`; `{\"type\": \"media\", \"data\": b\"...\"}` without `mime_type`; VertexAI payloads where `data` is `None` and was dropped by a dict-compaction step.","commonSituations":"Converting Gemini/VertexAI multimodal histories to OpenAI format; storing media blocks in JSON (bytes are not JSON-serializable, so `data` gets stripped) and reloading them for conversion.","solutions":["Include both keys: `{\"type\": \"media\", \"mime_type\": \"image/png\", \"data\": b\"<raw bytes>\"}`.","If blocks round-trip through JSON, base64-encode and decode `data` explicitly yourself, or switch to OpenAI `image_url` blocks which are JSON-safe.","Verify `mime_type` contains `image` — non-image media fails the next check (error 168) even with both keys present."],"exampleFix":"// before\n{\"type\": \"media\", \"mime_type\": \"video/mp4\", \"data\": raw}\n\n// after (image only)\n{\"type\": \"media\", \"mime_type\": \"image/png\", \"data\": raw}\n// or JSON-safe OpenAI form:\n{\"type\": \"image_url\", \"image_url\": {\"url\": f\"data:image/png;base64,{b64}\"}}","handlingStrategy":"validation","validationCode":"def valid_media_block(b: dict) -> bool:\n    return b.get(\"type\") == \"media\" and \"mime_type\" in b and \"data\" in b\n\nfor b in blocks:\n    if b.get(\"type\") == \"media\" and not valid_media_block(b):\n        raise ValueError(f\"media block missing keys: {b}\")","typeGuard":"def is_complete_media_block(b: dict) -> bool:\n    return (\n        b.get(\"type\") == \"media\"\n        and isinstance(b.get(\"mime_type\"), str)\n        and (\"data\" in b)\n    )","tryCatchPattern":null,"preventionTips":["Never persist media blocks as plain JSON without encoding bytes yourself","Prefer OpenAI image_url blocks for JSON-safe storage","Always set mime_type explicitly when constructing media blocks"],"tags":["messages","content-blocks","vertexai","multimodal","validation"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}