Skip to content

fix(models/anthropic): suppress Pydantic serialization warnings during serialization#2995

Open
lizradway wants to merge 2 commits into
strands-agents:mainfrom
lizradway:lizradway/rebase-pr-2821
Open

fix(models/anthropic): suppress Pydantic serialization warnings during serialization#2995
lizradway wants to merge 2 commits into
strands-agents:mainfrom
lizradway:lizradway/rebase-pr-2821

Conversation

@lizradway

Copy link
Copy Markdown
Member

Description

When using the Anthropic SDK >= 0.84.0, every streaming response triggers multiple PydanticSerializationUnexpectedValue warnings on stderr because model_dump() encounters ParsedTextBlock objects that don't match the discriminated union schema.

The previous fix (from #1746) worked around this by manually building dicts for message_stop and content_block_stop events, but the same warnings still fire for message_start, content_block_start, and content_block_delta.

This PR replaces those per-event-type workarounds with a single warnings.filterwarnings("ignore", message=".*PydanticSerializationUnexpectedValue.*") scoped to the model_dump() call. The serialization still produces correct data — it just emits noise that we suppress.

Related Issues

Fixes #1865

Documentation PR

N/A

Type of Change

Bug fix

Testing

Existing regression tests (test_stream_message_stop_no_pydantic_warnings, test_stream_content_block_stop_no_pydantic_warnings) already verify that Pydantic serialization warnings do not leak during streaming. Both pass with this change.

Added new regression test as well.

  • I ran hatch run prepare

Checklist

  • I have read the CONTRIBUTING document
  • I have reviewed and understand every line of code in this PR, including any generated by AI tools, and I can explain why it works
  • My change is focused and reasonably small; I have split unrelated work into separate PRs
  • I have added any necessary tests that prove my fix is effective or my feature works
  • I have updated the documentation accordingly
  • I have added an appropriate example to the documentation to outline the feature, or no new docs are needed
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

…g streaming

Suppress PydanticSerializationUnexpectedValue warnings emitted by model_dump()
when the Anthropic SDK (>=0.84.0) returns ParsedTextBlock objects in streaming
responses. This replaces the previous per-event-type workarounds with a single
warnings filter scoped to the model_dump() call.

Fixes strands-agents#1865
Adds test_stream_all_events_no_pydantic_warnings which verifies that
PydanticSerializationUnexpectedValue warnings are suppressed for all
event types (message_start, content_block_start, content_block_delta,
content_block_stop, message_stop) during streaming.
@github-actions github-actions Bot added size/s python Pull requests that update python code bug Something isn't working area-model Related to models or model providers strands-running labels Jun 28, 2026
@codecov

codecov Bot commented Jun 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

pydantic_warnings = [w for w in caught_warnings if "PydanticSerializationUnexpectedValue" in str(w.message)]
assert len(pydantic_warnings) == 0, f"Unexpected Pydantic warnings: {pydantic_warnings}"

assert {"messageStart": {"role": "assistant"}} in events

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue: These five assert {...} in events checks assert event-by-event. Since this test fully controls the mock model_dump() return values, the expected event sequence is known and deterministic, so the in checks silently miss ordering, missing events, or unexpected extra events (including the trailing metadata event). Per TESTING.md: "When you control the shape, assert the whole object — not field-by-field."

Suggestion: Build the expected list and assert in a single equality, e.g. tru_events = events / exp_events = [ ... ] then assert tru_events == exp_events. This documents the full expected stream and catches regressions the per-event membership checks would miss.

else:
with warnings.catch_warnings():
warnings.filterwarnings("ignore", message=".*PydanticSerializationUnexpectedValue.*")
yield self.format_chunk(event.model_dump())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue: The yield happens inside the with warnings.catch_warnings() block. catch_warnings() saves and mutates the global warnings filter state and only restores it on __exit__. Because a generator suspends at yield with the context manager still on the stack, the modified global filter stays active the entire time the consumer processes the chunk — and across any await/task switch that happens in between. With two streams interleaving, the nested save/restore of the global state can leak/restore the wrong filter (catch_warnings is explicitly documented as not thread/concurrency-safe). Only model_dump() actually needs suppression.

Suggestion: Compute the dump inside the context and yield outside it:

with warnings.catch_warnings():
    warnings.filterwarnings("ignore", message=".*PydanticSerializationUnexpectedValue.*")
    chunk = event.model_dump()
yield self.format_chunk(chunk)

@github-actions

Copy link
Copy Markdown
Contributor

Assessment: Comment

Clean, focused bug fix that collapses the per-event-type workarounds into a single scoped suppression — the message-regex scope is appropriately narrow. One correctness/robustness concern around where the yield sits relative to the catch_warnings context, plus a couple of test-quality refinements.

Review themes
  • Correctness/robustness: Yielding inside the warnings.catch_warnings() block holds the mutated global warnings filter across the yield boundary and any concurrent task switch; suppress only around model_dump().
  • Testing: New all-events test uses per-event membership assertions where a single full-sequence equality would be more rigorous (per TESTING.md); some overlap with the two existing per-event regression tests worth consolidating.

Nice simplification overall — removing the special-cased event handling makes stream() much easier to follow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-model Related to models or model providers bug Something isn't working python Pull requests that update python code size/s

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Strands Agent AnthropicModel emits Pydantic serialization warnings with Anthropic SDK v0.84.0

1 participant