Checks
Strands Version
1.27.0
Python Version
3.13
Operating System
Debian 13.1
Installation Method
pip
Steps to Reproduce
Install Strands with the anthopic extra version 0.83.0. Then run:
import os
from strands import Agent
from strands.models.anthropic import AnthropicModel
api_key = os.environ.get("ANTHROPIC_API_KEY")
model = AnthropicModel(
client_args={"api_key": api_key},
model_id="claude-sonnet-4-20250514",
max_tokens=1024,
)
agent = Agent(model=model, callback_handler=None)
result = agent("Say hello in one sentence.")
Running that script will print a bunch of pydantic warnings.
Expected Behavior
No warnings printed. I don't think this is breaking anything.
Actual Behavior
Here are the warnings:
/workspace/.venv/lib/python3.13/site-packages/pydantic/main.py:464: UserWarning: Pydantic serializer warnings:
PydanticSerializationUnexpectedValue(Expected `ParsedTextBlock[TypeVar]` - serialized value may not be as expected [field_name='content', input_value=ParsedTextBlock(citations...xt', parsed_output=None), input_type=ParsedTextBlock])
PydanticSerializationUnexpectedValue(Expected `ThinkingBlock` - serialized value may not be as expected [field_name='content', input_value=ParsedTextBlock(citations...xt', parsed_output=None), input_type=ParsedTextBlock])
PydanticSerializationUnexpectedValue(Expected `RedactedThinkingBlock` - serialized value may not be as expected [field_name='content', input_value=ParsedTextBlock(citations...xt', parsed_output=None), input_type=ParsedTextBlock])
PydanticSerializationUnexpectedValue(Expected `ToolUseBlock` - serialized value may not be as expected [field_name='content', input_value=ParsedTextBlock(citations...xt', parsed_output=None), input_type=ParsedTextBlock])
PydanticSerializationUnexpectedValue(Expected `ServerToolUseBlock` - serialized value may not be as expected [field_name='content', input_value=ParsedTextBlock(citations...xt', parsed_output=None), input_type=ParsedTextBlock])
PydanticSerializationUnexpectedValue(Expected `WebSearchToolResultBlock` - serialized value may not be as expected [field_name='content', input_value=ParsedTextBlock(citations...xt', parsed_output=None), input_type=ParsedTextBlock])
return self.__pydantic_serializer__.to_python(
anthropic.types.ParsedTextBlock is a Pydantic BaseModel (inherits from TextBlock), while ContentBlock is a TypedDict. Pydantic's serializer doesn't know how to match a BaseModel instance against a TypedDict variant in a union, so it tries every variant and warns for each one.
Additional Context
No response
Possible Solution
No response
Related Issues
No response
Implementation Requirements
Root Cause
The issue originates in src/strands/models/anthropic.py in the stream() method (line ~410):
async for event in stream:
if event.type in AnthropicModel.EVENT_TYPES:
yield self.format_chunk(event.model_dump()) # Problem is here
For message_stop events, calling event.model_dump() serializes the entire event including event.message, which contains a content field with ParsedTextBlock objects. Pydantic can't cleanly serialize ParsedTextBlock (a Pydantic BaseModel) against the TypedDict union variants, generating warnings.
Key insight: The format_chunk method for message_stop only needs stop_reason:
case "message_stop":
message = event["message"]
return {"messageStop": {"stopReason": message["stop_reason"]}}
Technical Approach - Fix the Root Cause
Instead of suppressing warnings, avoid the unnecessary serialization entirely. For message_stop events, build the dict directly from the event attributes instead of calling model_dump().
# Before (causes warnings - serializes entire message including content)
async for event in stream:
if event.type in AnthropicModel.EVENT_TYPES:
yield self.format_chunk(event.model_dump())
# After (fixes root cause - only extracts what we need)
async for event in stream:
if event.type in AnthropicModel.EVENT_TYPES:
if event.type == "message_stop":
# Build dict directly - avoids serializing problematic content field
yield self.format_chunk({
"type": "message_stop",
"message": {"stop_reason": event.message.stop_reason}
})
else:
yield self.format_chunk(event.model_dump())
Why This Approach Is Best
| Aspect |
warnings=False |
Targeted Filter |
Root Cause Fix |
| Fixes the actual problem |
❌ Workaround |
❌ Workaround |
✅ Yes |
| No warning suppression |
❌ |
❌ |
✅ |
| Risk of masking issues |
⚠️ High |
⚠️ Medium |
✅ None |
| More efficient |
❌ |
❌ |
✅ Less data serialized |
| Clean/explicit |
❌ |
⚠️ |
✅ Yes |
Files to Modify
-
src/strands/models/anthropic.py
- Lines ~408-410: Add conditional handling for
message_stop events
- Build dict directly from
event.message.stop_reason instead of calling model_dump()
-
tests/strands/models/test_anthropic.py
- Add test to verify no warnings are emitted during streaming with
message_stop events
- Verify the
message_stop event is still processed correctly
Code Change
# In stream() method, replace:
async for event in stream:
if event.type in AnthropicModel.EVENT_TYPES:
yield self.format_chunk(event.model_dump())
# With:
async for event in stream:
if event.type in AnthropicModel.EVENT_TYPES:
if event.type == "message_stop":
yield self.format_chunk({
"type": "message_stop",
"message": {"stop_reason": event.message.stop_reason}
})
else:
yield self.format_chunk(event.model_dump())
Acceptance Criteria
Testing Notes
- Use
warnings.catch_warnings(record=True) in tests to verify no warnings
- Test should use mock events that simulate the
message_stop event structure
- Verify the formatted output is identical to before (same
stopReason value)
Checks
Strands Version
1.27.0
Python Version
3.13
Operating System
Debian 13.1
Installation Method
pip
Steps to Reproduce
Install Strands with the anthopic extra version 0.83.0. Then run:
Running that script will print a bunch of pydantic warnings.
Expected Behavior
No warnings printed. I don't think this is breaking anything.
Actual Behavior
Here are the warnings:
anthropic.types.ParsedTextBlock is a Pydantic BaseModel (inherits from TextBlock), while ContentBlock is a TypedDict. Pydantic's serializer doesn't know how to match a BaseModel instance against a TypedDict variant in a union, so it tries every variant and warns for each one.
Additional Context
No response
Possible Solution
No response
Related Issues
No response
Implementation Requirements
Root Cause
The issue originates in
src/strands/models/anthropic.pyin thestream()method (line ~410):For
message_stopevents, callingevent.model_dump()serializes the entire event includingevent.message, which contains acontentfield withParsedTextBlockobjects. Pydantic can't cleanly serializeParsedTextBlock(a PydanticBaseModel) against theTypedDictunion variants, generating warnings.Key insight: The
format_chunkmethod formessage_stoponly needsstop_reason:Technical Approach - Fix the Root Cause
Instead of suppressing warnings, avoid the unnecessary serialization entirely. For
message_stopevents, build the dict directly from the event attributes instead of callingmodel_dump().Why This Approach Is Best
warnings=FalseFiles to Modify
src/strands/models/anthropic.pymessage_stopeventsevent.message.stop_reasoninstead of callingmodel_dump()tests/strands/models/test_anthropic.pymessage_stopeventsmessage_stopevent is still processed correctlyCode Change
Acceptance Criteria
PydanticSerializationUnexpectedValuewarnings when usingAnthropicModelmessage_stophandling without warningsTesting Notes
warnings.catch_warnings(record=True)in tests to verify no warningsmessage_stopevent structurestopReasonvalue)