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

ListOutputParser And XMLOutputParser Streaming Silently Drop Messages With List Content

Streaming through ListOutputParser or XMLOutputParser silently yields nothing when message chunks contain list content (content blocks), while invoke() on the same content parses correctly. This affects Anthropic chat models and causes silent data loss.

highConfidence 95%Langchain-CoreAffected V1.5.6

Origin Analysis

Both parsers guard streaming with `isinstance(message.content, str)` and skip non-string content. Content blocks (list of dicts) are non-string, so all text is dropped. The non-streaming path extracts text via `message.text`, which handles content blocks; the streaming path should use the same extraction.
Run the provided example: ```python from langchain_core.messages import AIMessage, AIMessageChunk from langchain_core.output_parsers import CommaSeparatedListOutputParser parser = CommaSeparatedListOutputParser() message = AIMessage(content=[{"type": "text", "text": "red, green, blue"}]) print("invoke: ", parser.invoke(message)) chunks = [ AIMessageChunk(content=[{"type": "text", "text": "red, gre", "index": 0}]), AIMessageChunk(content=[{"type": "text", "text": "en, blue", "index": 0}]), ] print("transform:", list(parser.transform(iter(chunks)))) ``` Expected: transform yields [['red'], ['green'], ['blue']], but actual is []. Also reproducible with XMLOutputParser and Anthropic streaming content blocks.

Fixing Code Block

Edge Case Audit

Empty text from tool-call-only chunks may still be emitted as an empty list (for ListOutputParser) or cause XML parsing errors if `parse('')` is not handled. Add a guard to skip if `not text` when tool calls are expected in the stream. Roll back by restoring the original `isinstance` check and `continue`/`return {}`. The change is source-level and compatible with Python 3.9+; no database or deployment rollback needed beyond reverting the PR.

Ecosystem Topology