AI & Agent Dev Bug Sandbox logo
AI & Agent Dev Bug Sandbox
Back to Radar

Langchain-Openrouter Sends ToolMessage Content Blocks (E.G. Images) Unconverted, Causing Client-Side ValidationError

ToolMessage content that contains standard LangChain content blocks (like images) is forwarded to the OpenRouter API without conversion, leading to a client-side ValidationError. This makes agent threads unrecoverable until history is trimmed.

highConfidence 95%LangchainAffected V<=0.2.8

Origin Analysis

In langchain_openrouter's _convert_message_to_dict, _format_message_content is applied only for HumanMessage. The ToolMessage branch forwards message.content verbatim, so standard 'image' blocks are not mapped to OpenRouter's expected 'image_url' tag, causing the OpenRouter SDK to reject the payload during validation.
1. Install langchain-openrouter (tested on 0.2.8) and langchain-core. 2. Create a ChatOpenRouter instance with a dummy API key. 3. Build a conversation with a HumanMessage, an AIMessage containing a tool_call, and a ToolMessage whose content is a list containing an image block: [{"type": "image", "base64": <valid base64>, "mime_type": "image/png"}]. 4. Call llm.invoke(messages). 5. Observe ValidationError before any network request. A text-only ToolMessage passes validation and fails later with 401 (dummy key).

Fixing Code Block

Edge Case Audit

Applying _format_message_content to ToolMessage may introduce edge cases if _format_message_content assumes user-message semantics (e.g. it might reject certain block types or alter formatting). Test with various tool result content types (text, image_url, file, audio) and across multiple OpenRouter models. The change is backward-compatible for string content. Rollback: revert to original branch that passes content verbatim. If the function raises on unsupported blocks, consider adding a fallback that converts only known safe types or logs a warning and sends a placeholder.

Ecosystem Topology