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

Pydantic Serializer Warnings When Streaming With Structured Output Due To Invalid Parsed Field On AIMessageChunk

When using ChatOpenAI with with_structured_output and streaming=True, LangChain emits a UserWarning from Pydantic during serialization of an AIMessageChunk. The warning indicates that the 'parsed' field contains a BaseModel instance while the field type expects None. The output is still produced correctly, but the warning pollutes logs and indicates a type mismatch in the streaming path.

mediumConfidence 85%LangChainAffected Vlangchain-Openai 1.3.0Affected Vlangchain-Core 1.4.3

Origin Analysis

In langchain_openai/chat_models/base.py, the _stream method constructs AIMessageChunk objects with a parsed argument set to a fully parsed Pydantic model (e.g., ModelOutput). However, AIMessageChunk's parsed field is typed as None (or Optional[None]) to avoid carrying parsed data in streaming chunks. Assigning a non-None value bypasses validation (likely via model_construct) and triggers Pydantic serialization warnings when the chunk is serialized.
1. Install langchain-openai 1.3.0, langchain-core 1.4.3, and pydantic 2.x. 2. Run the provided Python snippet: ```python from langchain_openai import ChatOpenAI from pydantic import BaseModel llm = ChatOpenAI(model='gpt-5.4', streaming=True) class ModelOutput(BaseModel): output: str print(llm.with_structured_output(ModelOutput).invoke('What is the capital of France?')) ``` 3. Observe the Pydantic UserWarning: Expected `none` - serialized value may not be as expected [field_name='parsed', input_value=ModelOutput(...), input_type=ModelOutput].

Fixing Code Block

Apply the following minimal patch to langchain_openai/chat_models/base.py in the _stream method: locate the construction of AIMessageChunk and remove the parsed=parsed argument. ```diff --- a/libs/partners/openai/langchain_openai/chat_models/base.py +++ b/libs/partners/openai/langchain_openai/chat_models/base.py @@ -1670,7 +1670,6 @@ class ChatOpenAI(BaseChatModel): message=AIMessageChunk( content=text, tool_call_chunks=tool_call_chunks, - parsed=parsed, ) ) ```
Removing the parsed=parsed keyword argument from the AIMessageChunk constructor ensures that streaming chunks do not carry a full parsed model instance. The parsed field on AIMessageChunk is intentionally restricted to None to avoid serialization overhead and type mismatches. The structured output parser that wraps the model will still reconstruct the final parsed model after all chunks are aggregated, preserving functionality while eliminating the warning.

Edge Case Audit

This hotfix only removes the invalid field assignment; it does not affect the final structured output parsing. However, ensure that the wrapping StructuredOutputParser is present and functioning (as it is when using with_structured_output). If custom code directly consumes AIMessageChunk objects expecting the parsed attribute to be populated during streaming, it will break. Rollback is straightforward: re-add the parsed=parsed line. For long-term fix, consider updating AIMessageChunk.parsed type to Optional[BaseModel] in langchain-core if needed, but that may have broader implications. This patch is safe for the standard with_structured_output usage.

Ecosystem Topology