From b6eb991b3bfd03ed4c84afa46fc1a0f76cd5b943 Mon Sep 17 00:00:00 2001 From: Alexander Alderman Webb Date: Fri, 20 Feb 2026 11:32:19 +0100 Subject: [PATCH 1/4] fix(openai): Avoid consuming iterables passed to Completions API --- sentry_sdk/integrations/openai.py | 22 ++++++--- tests/integrations/openai/test_openai.py | 60 ++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 7 deletions(-) diff --git a/sentry_sdk/integrations/openai.py b/sentry_sdk/integrations/openai.py index 863f146a51..37a5914029 100644 --- a/sentry_sdk/integrations/openai.py +++ b/sentry_sdk/integrations/openai.py @@ -371,13 +371,6 @@ def _set_completions_api_input_data( _commmon_set_input_data(span, kwargs) return - system_instructions = _get_system_instructions_completions(messages) - if len(system_instructions) > 0: - span.set_data( - SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, - json.dumps(_transform_system_instructions(system_instructions)), - ) - if isinstance(messages, str): normalized_messages = normalize_message_roles([messages]) # type: ignore scope = sentry_sdk.get_current_scope() @@ -390,6 +383,21 @@ def _set_completions_api_input_data( _commmon_set_input_data(span, kwargs) return + if not isinstance(messages, Iterable): + set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "chat") + _commmon_set_input_data(span, kwargs) + return + + messages = list(messages) + kwargs["messages"] = messages + + system_instructions = _get_system_instructions_completions(messages) + if len(system_instructions) > 0: + span.set_data( + SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, + json.dumps(_transform_system_instructions(system_instructions)), + ) + non_system_messages = [ message for message in messages diff --git a/tests/integrations/openai/test_openai.py b/tests/integrations/openai/test_openai.py index 094b659b2c..1202c50373 100644 --- a/tests/integrations/openai/test_openai.py +++ b/tests/integrations/openai/test_openai.py @@ -204,6 +204,21 @@ def test_nonstreaming_chat_completion_no_prompts( ], id="parts", ), + pytest.param( + iter( + [ + { + "role": "system", + "content": [ + {"type": "text", "text": "You are a helpful assistant."}, + {"type": "text", "text": "Be concise and clear."}, + ], + }, + {"role": "user", "content": "hello"}, + ] + ), + id="iterator", + ), ], ) def test_nonstreaming_chat_completion(sentry_init, capture_events, messages, request): @@ -335,6 +350,21 @@ async def test_nonstreaming_chat_completion_async_no_prompts( ], id="parts", ), + pytest.param( + iter( + [ + { + "role": "system", + "content": [ + {"type": "text", "text": "You are a helpful assistant."}, + {"type": "text", "text": "Be concise and clear."}, + ], + }, + {"role": "user", "content": "hello"}, + ] + ), + id="iterator", + ), ], ) async def test_nonstreaming_chat_completion_async( @@ -521,6 +551,21 @@ def test_streaming_chat_completion_no_prompts( ], id="parts", ), + pytest.param( + iter( + [ + { + "role": "system", + "content": [ + {"type": "text", "text": "You are a helpful assistant."}, + {"type": "text", "text": "Be concise and clear."}, + ], + }, + {"role": "user", "content": "hello"}, + ] + ), + id="iterator", + ), ], ) def test_streaming_chat_completion(sentry_init, capture_events, messages, request): @@ -757,6 +802,21 @@ async def test_streaming_chat_completion_async_no_prompts( ], id="parts", ), + pytest.param( + iter( + [ + { + "role": "system", + "content": [ + {"type": "text", "text": "You are a helpful assistant."}, + {"type": "text", "text": "Be concise and clear."}, + ], + }, + {"role": "user", "content": "hello"}, + ] + ), + id="iterator", + ), ], ) async def test_streaming_chat_completion_async( From 6484710e5d98c2997df3168fa7f970b997867c2c Mon Sep 17 00:00:00 2001 From: Alexander Alderman Webb Date: Fri, 20 Feb 2026 11:37:31 +0100 Subject: [PATCH 2/4] unused type ignore --- sentry_sdk/integrations/openai.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry_sdk/integrations/openai.py b/sentry_sdk/integrations/openai.py index 37a5914029..2817584ab8 100644 --- a/sentry_sdk/integrations/openai.py +++ b/sentry_sdk/integrations/openai.py @@ -404,7 +404,7 @@ def _set_completions_api_input_data( if not _is_system_instruction_completions(message) ] if len(non_system_messages) > 0: - normalized_messages = normalize_message_roles(non_system_messages) # type: ignore + normalized_messages = normalize_message_roles(non_system_messages) scope = sentry_sdk.get_current_scope() messages_data = truncate_and_annotate_messages(normalized_messages, span, scope) if messages_data is not None: From 2b58e655e3b3d9d4c1c9a10ab7a7eac1d37b6114 Mon Sep 17 00:00:00 2001 From: Alexander Alderman Webb Date: Fri, 20 Feb 2026 15:07:38 +0100 Subject: [PATCH 3/4] add dict edge case --- sentry_sdk/integrations/openai.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sentry_sdk/integrations/openai.py b/sentry_sdk/integrations/openai.py index 2817584ab8..e27f411838 100644 --- a/sentry_sdk/integrations/openai.py +++ b/sentry_sdk/integrations/openai.py @@ -383,7 +383,8 @@ def _set_completions_api_input_data( _commmon_set_input_data(span, kwargs) return - if not isinstance(messages, Iterable): + # Special case following https://github.com/openai/openai-python/blob/3e0c05b84a2056870abf3bd6a5e7849020209cc3/src/openai/_utils/_transform.py#L194-L197 + if not isinstance(messages, Iterable) or isinstance(messages, dict): set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "chat") _commmon_set_input_data(span, kwargs) return From ec29f16922af3d19ab580f914f66abf13fb3b48b Mon Sep 17 00:00:00 2001 From: Alexander Alderman Webb Date: Fri, 20 Feb 2026 15:09:29 +0100 Subject: [PATCH 4/4] . --- sentry_sdk/integrations/openai.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry_sdk/integrations/openai.py b/sentry_sdk/integrations/openai.py index e27f411838..cfd36b84dd 100644 --- a/sentry_sdk/integrations/openai.py +++ b/sentry_sdk/integrations/openai.py @@ -383,7 +383,7 @@ def _set_completions_api_input_data( _commmon_set_input_data(span, kwargs) return - # Special case following https://github.com/openai/openai-python/blob/3e0c05b84a2056870abf3bd6a5e7849020209cc3/src/openai/_utils/_transform.py#L194-L197 + # dict special case following https://github.com/openai/openai-python/blob/3e0c05b84a2056870abf3bd6a5e7849020209cc3/src/openai/_utils/_transform.py#L194-L197 if not isinstance(messages, Iterable) or isinstance(messages, dict): set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "chat") _commmon_set_input_data(span, kwargs)