fix(anthropic): guard file-id discovery against malformed content blocks

get_file_ids_from_messages iterated user message content and indexed
c["type"] with no check that each item is a dict or that the key exists.
Because AnthropicConfig.validate_environment calls it unconditionally via
is_file_id_used, a single malformed content block crashed request building
for every Anthropic, Bedrock-Claude, Vertex-Anthropic and Azure-AI-Anthropic
completion:

- a block dict missing "type" raised KeyError
- a non-dict list item (e.g. token-id lists forwarded by text_completion)
  raised TypeError: list indices must be integers
- a bare string item raised TypeError: string indices must be integers

Skip non-dict items and read "type" with .get(), mirroring the already
hardened sibling update_messages_with_model_file_ids in the same module.
Well-formed OpenAI file blocks still yield their file_id unchanged.

Signed-off-by: Anas Khan <83116240+anxkhn@users.noreply.github.com>
This commit is contained in:
Anas Khan 2026-07-06 18:35:25 +05:30
parent b9008cca35
commit 3bbfe7e75d
No known key found for this signature in database
2 changed files with 29 additions and 1 deletions

View file

@ -1238,7 +1238,9 @@ def get_file_ids_from_messages(messages: List[AllMessageValues]) -> List[str]:
if isinstance(content, str):
continue
for c in content:
if c["type"] == "file":
if not isinstance(c, dict):
continue
if c.get("type") == "file":
file_object = cast(ChatCompletionFileObject, c)
file_object_file_field = file_object.get("file")
if not isinstance(file_object_file_field, dict):

View file

@ -343,6 +343,32 @@ def test_get_file_ids_from_messages_file_field_not_dict():
assert get_file_ids_from_messages(messages) == []
def test_get_file_ids_from_messages_content_block_without_type():
"""A content block dict that omits `type` must not raise KeyError."""
messages = [
{
"role": "user",
"content": [
{"text": "hi"},
{"type": "file", "file": {"file_id": "file-keep"}},
],
}
]
assert get_file_ids_from_messages(messages) == ["file-keep"]
def test_get_file_ids_from_messages_non_dict_content_items():
"""Non-dict content items (e.g. token-id lists forwarded by
text_completion, or bare strings) must be skipped, not indexed into."""
messages = [
{"role": "user", "content": [[1, 2, 3]]},
{"role": "user", "content": ["hello"]},
]
assert get_file_ids_from_messages(messages) == []
def test_update_messages_with_model_file_ids_skips_non_openai_file_blocks():
"""`update_messages_with_model_file_ids` is also called on user content
before provider dispatch. It must tolerate non-OpenAI file blocks the same