Skip to content

fix: resolve subscripted generics in _build_discriminated_union_meta (pydantic v1)#1238

Open
ohxh wants to merge 1 commit intoanthropics:mainfrom
ohxh:fix/pydantic-v1-subscripted-generic-fields
Open

fix: resolve subscripted generics in _build_discriminated_union_meta (pydantic v1)#1238
ohxh wants to merge 1 commit intoanthropics:mainfrom
ohxh:fix/pydantic-v1-subscripted-generic-fields

Conversation

@ohxh
Copy link

@ohxh ohxh commented Mar 11, 2026

Problem

_build_discriminated_union_meta in _models.py accesses variant.__fields__ directly on each Union variant. When a variant is a subscripted generic like ParsedBetaTextBlock[ResponseFormatT] (from ParsedBetaContentBlock), it is a typing._GenericAlias — not a class — so .__fields__ raises AttributeError on Python 3.12.

This crashes streaming (client.beta.messages.stream()) because accumulate_event calls construct_type(type_=ParsedBetaContentBlock, ...) on every content_block_start event, and when pydantic v1's validate_type fails to parse the block, it falls through to _build_discriminated_union_meta which hits this bug.

Only the pydantic v1 code path is affected. Pydantic v2 uses _extract_field_schema_pv2 which handles subscripted generics correctly.

Fix

Use get_origin(variant) or variant before accessing .__fields__, matching the pattern the SDK's own is_basemodel_type already uses (line 460):

# Before (crashes on subscripted generics):
field_info = cast(..., variant.__fields__).get(discriminator_field_name)

# After:
origin = get_origin(variant) or variant
field_info = cast(..., origin.__fields__).get(discriminator_field_name)

Repro

# With pydantic v1 installed:
client = anthropic.Anthropic()
with client.beta.messages.stream(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[{"role": "user", "content": "hello"}],
    betas=["..."],
) as stream:
    for event in stream:  # AttributeError: __fields__
        pass
AttributeError: __fields__
  File "anthropic/lib/streaming/_beta_messages.py", line 133, in __stream__
    self.__final_message_snapshot = accumulate_event(...)
  File "anthropic/lib/streaming/_beta_messages.py", line 481, in accumulate_event
    construct_type(type_=ParsedBetaContentBlock, value=event.content_block.to_dict())
  File "anthropic/_models.py", line 549, in construct_type
    discriminator = _build_discriminated_union_meta(union=type_, meta_annotations=meta)
  File "anthropic/_models.py", line 689, in _build_discriminated_union_meta
    field_info = cast(..., variant.__fields__).get(discriminator_field_name)
  File "typing.py", line 1186, in __getattr__
    raise AttributeError(attr)

Made with Cursor

…(pydantic v1)

`_build_discriminated_union_meta` accesses `variant.__fields__` directly
on each Union variant. When a variant is a subscripted generic like
`ParsedBetaTextBlock[ResponseFormatT]`, it is a `typing._GenericAlias`
(not a class) and `.__fields__` raises `AttributeError` on Python 3.12.

The SDK's own `is_basemodel_type` (line 460) already handles this by
using `get_origin(type_) or type_` to extract the origin class before
inspecting it. This applies the same pattern to the pydantic v1 branch
of `_build_discriminated_union_meta`.

Only the pydantic v1 code path is affected; pydantic v2 uses
`_extract_field_schema_pv2` which handles generics correctly.

Made-with: Cursor
@ohxh ohxh requested a review from a team as a code owner March 11, 2026 06:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant