From ab9f0eef9f6a0cc72f8f6c6ef7b0bd70cf35c999 Mon Sep 17 00:00:00 2001 From: Kian Khooban Date: Wed, 3 Jun 2026 18:46:41 -0400 Subject: [PATCH 1/2] fix: guard against bare unparameterized dict/list in construct_type and transform get_args(dict) and get_args(list) return empty tuples when no type parameters are present. Four sites were unconditionally indexing into those tuples, crashing with ValueError or IndexError. - _models.py: use already-computed `args` with len-guard for dict branch; add `if args` guard for list branch - _utils/_transform.py: guard both sync and async dict branches Fixes #1619, #1626, #1628 --- src/anthropic/_models.py | 4 ++-- src/anthropic/_utils/_transform.py | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/anthropic/_models.py b/src/anthropic/_models.py index dc00516bc..b9b80256d 100644 --- a/src/anthropic/_models.py +++ b/src/anthropic/_models.py @@ -647,7 +647,7 @@ def construct_type(*, value: object, type_: object, metadata: Optional[List[Any] if not is_mapping(value): return value - _, items_type = get_args(type_) # Dict[_, items_type] + items_type = args[1] if len(args) >= 2 else object # Dict[_, items_type] return {key: construct_type(value=item, type_=items_type) for key, item in value.items()} if ( @@ -668,7 +668,7 @@ def construct_type(*, value: object, type_: object, metadata: Optional[List[Any] if not is_list(value): return value - inner_type = args[0] # List[inner_type] + inner_type = args[0] if args else object # List[inner_type] return [construct_type(value=entry, type_=inner_type) for entry in value] if origin == float: diff --git a/src/anthropic/_utils/_transform.py b/src/anthropic/_utils/_transform.py index 1e7e5ac80..0b1ef65b2 100644 --- a/src/anthropic/_utils/_transform.py +++ b/src/anthropic/_utils/_transform.py @@ -180,7 +180,8 @@ def _transform_recursive( return _transform_typeddict(data, stripped_type) if origin == dict and is_mapping(data): - items_type = get_args(stripped_type)[1] + _args = get_args(stripped_type) + items_type = _args[1] if len(_args) >= 2 else object return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()} if ( @@ -346,7 +347,8 @@ async def _async_transform_recursive( return await _async_transform_typeddict(data, stripped_type) if origin == dict and is_mapping(data): - items_type = get_args(stripped_type)[1] + _args = get_args(stripped_type) + items_type = _args[1] if len(_args) >= 2 else object return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()} if ( From 26eea24e7350b4cd12cc27831669d323796ee25a Mon Sep 17 00:00:00 2001 From: Kian Khooban Date: Wed, 3 Jun 2026 18:54:43 -0400 Subject: [PATCH 2/2] fixup: address Copilot review comments on _transform.py - Rename _args to args for consistency with rest of codebase - Fix pre-existing bug: async dict branch was calling _transform_recursive instead of _async_transform_recursive, skipping async recursion for nested dict values; switch to await _async_transform_recursive --- src/anthropic/_utils/_transform.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/anthropic/_utils/_transform.py b/src/anthropic/_utils/_transform.py index 0b1ef65b2..75b09393f 100644 --- a/src/anthropic/_utils/_transform.py +++ b/src/anthropic/_utils/_transform.py @@ -180,8 +180,8 @@ def _transform_recursive( return _transform_typeddict(data, stripped_type) if origin == dict and is_mapping(data): - _args = get_args(stripped_type) - items_type = _args[1] if len(_args) >= 2 else object + args = get_args(stripped_type) + items_type = args[1] if len(args) >= 2 else object return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()} if ( @@ -347,9 +347,9 @@ async def _async_transform_recursive( return await _async_transform_typeddict(data, stripped_type) if origin == dict and is_mapping(data): - _args = get_args(stripped_type) - items_type = _args[1] if len(_args) >= 2 else object - return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()} + args = get_args(stripped_type) + items_type = args[1] if len(args) >= 2 else object + return {key: await _async_transform_recursive(value, annotation=items_type) for key, value in data.items()} if ( # List[T]