From eb6164ca7de53a2d7170ae7473a72fe2c07ad80d Mon Sep 17 00:00:00 2001 From: Natalie Kong <186588905+Nataliekooong@users.noreply.github.com> Date: Fri, 25 Sep 2026 17:56:28 -0400 Subject: [PATCH 1/2] fix(streaming): skip pydantic model_* attributes before getattr in stream emptiness check --- .../model_response_utils.py | 9 +++-- .../test_model_response_utils.py | 35 +++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/litellm/litellm_core_utils/model_response_utils.py b/litellm/litellm_core_utils/model_response_utils.py index dc4f375daa7..a378c160077 100644 --- a/litellm/litellm_core_utils/model_response_utils.py +++ b/litellm/litellm_core_utils/model_response_utils.py @@ -158,8 +158,8 @@ def _is_choice_non_empty(choice: StreamingChoices) -> bool: # Skip private attributes, methods, and known empty fields if ( attr_name.startswith("_") - or callable(_attribute_of(choice, attr_name)) or attr_name.startswith("model_") + or callable(_attribute_of(choice, attr_name)) or attr_name in { "finish_reason", @@ -197,7 +197,12 @@ def _is_delta_non_empty(delta: Delta) -> bool: # Check all regular attributes of the delta object for attr_name in dir(delta): # Skip private attributes, methods, and Pydantic-specific fields - if attr_name.startswith("_") or callable(_attribute_of(delta, attr_name)) or attr_name.startswith("model_"): + if ( + attr_name.startswith("_") + or attr_name.startswith("model_") + or callable(_attribute_of(delta, attr_name)) + or attr_name.startswith("model_") + ): continue delta_attr_value: object = getattr(delta, attr_name, None) diff --git a/tests/test_litellm/litellm_core_utils/test_model_response_utils.py b/tests/test_litellm/litellm_core_utils/test_model_response_utils.py index 2ffe5853c4d..aff7c81ee07 100644 --- a/tests/test_litellm/litellm_core_utils/test_model_response_utils.py +++ b/tests/test_litellm/litellm_core_utils/test_model_response_utils.py @@ -1,3 +1,4 @@ +import warnings from litellm.litellm_core_utils.model_response_utils import ( is_model_response_stream_empty, ) @@ -58,3 +59,37 @@ def test_is_model_response_stream_empty_with_custom_value(): setattr(chunk.choices[0].delta, "custom_field", "test") assert is_model_response_stream_empty(chunk) is False + + + +def test_is_model_response_stream_empty_does_not_access_deprecated_pydantic_instance_attributes(): + chunk = ModelResponseStream( + id="chatcmpl-C3sWKN2RWbn6CZ1IGU2QCpRh4RhYf", + created=1755040596, + model="gpt-4o-mini", + object="chat.completion.chunk", + system_fingerprint="fp_34a54ae93c", + choices=[ + StreamingChoices( + finish_reason=None, + index=0, + delta=Delta( + provider_specific_fields=None, + content=None, + role=None, + function_call=None, + tool_calls=None, + audio=None, + ), + logprobs=None, + ) + ], + provider_specific_fields=None, + ) + + with warnings.catch_warnings(): + warnings.filterwarnings( + "error", + message=r".*'model_(computed_)?fields' attribute on the instance is deprecated", + ) + assert is_model_response_stream_empty(chunk) is True From 337e27f39bd17206602245ede91493be7f1542e7 Mon Sep 17 00:00:00 2001 From: Natalie Kong <186588905+Nataliekooong@users.noreply.github.com> Date: Sat, 26 Sep 2026 00:35:47 -0400 Subject: [PATCH 2/2] fix(streaming): drop redundant model_ prefix check in delta loop --- litellm/litellm_core_utils/model_response_utils.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/litellm/litellm_core_utils/model_response_utils.py b/litellm/litellm_core_utils/model_response_utils.py index a378c160077..77d85c52404 100644 --- a/litellm/litellm_core_utils/model_response_utils.py +++ b/litellm/litellm_core_utils/model_response_utils.py @@ -197,12 +197,7 @@ def _is_delta_non_empty(delta: Delta) -> bool: # Check all regular attributes of the delta object for attr_name in dir(delta): # Skip private attributes, methods, and Pydantic-specific fields - if ( - attr_name.startswith("_") - or attr_name.startswith("model_") - or callable(_attribute_of(delta, attr_name)) - or attr_name.startswith("model_") - ): + if attr_name.startswith("_") or attr_name.startswith("model_") or callable(_attribute_of(delta, attr_name)): continue delta_attr_value: object = getattr(delta, attr_name, None)