From 28d36b58fed2033a005831ae5dcaa593897053c4 Mon Sep 17 00:00:00 2001 From: Sergii Kalinchuk Date: Tue, 25 Nov 2025 10:10:23 +0200 Subject: [PATCH 1/4] fix(ai): Handle Pydantic model classes in _normalize_data Previously, _normalize_data would attempt to call model_dump() on Pydantic model classes (types) when they were passed as arguments, which would fail. This commonly occurs when model classes are used in schema definitions. This change adds an inspect.isclass() check to detect when a class type is passed instead of an instance. For classes, we now return a string representation "" instead of attempting to call model_dump(). --- sentry_sdk/ai/utils.py | 6 ++++++ tests/utils/test_general.py | 26 ++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/sentry_sdk/ai/utils.py b/sentry_sdk/ai/utils.py index 06c9a23604..cff738d679 100644 --- a/sentry_sdk/ai/utils.py +++ b/sentry_sdk/ai/utils.py @@ -1,3 +1,4 @@ +import inspect import json from collections import deque from typing import TYPE_CHECKING @@ -38,6 +39,11 @@ def _normalize_data(data, unpack=True): # type: (Any, bool) -> Any # convert pydantic data (e.g. OpenAI v1+) to json compatible format if hasattr(data, "model_dump"): + # Check if it's a class (type) rather than an instance + # Model classes can be passed as arguments (e.g., for schema definitions) + if inspect.isclass(data): + return f"" + try: return _normalize_data(data.model_dump(), unpack=unpack) except Exception as e: diff --git a/tests/utils/test_general.py b/tests/utils/test_general.py index 03182495de..a2846f4ddf 100644 --- a/tests/utils/test_general.py +++ b/tests/utils/test_general.py @@ -2,6 +2,7 @@ import os import pytest +from sentry_sdk.ai.utils import _normalize_data from sentry_sdk.utils import ( @@ -621,3 +622,28 @@ def test_failed_base64_conversion(input): ) def test_strip_string(input, max_length, result): assert strip_string(input, max_length) == result + + +def test_normalize_data_with_pydantic_class(): + """Test that _normalize_data handles Pydantic model classes""" + class TestClass: + name: str = None + + def __init__(self, name: str): + self.name = name + + def model_dump(self): + return {"name": self.name} + + # Test with class (should NOT call model_dump()) + result = _normalize_data(TestClass) + assert result == "" + + # Test with instance (should call model_dump()) + instance = TestClass(name="test") + result = _normalize_data(instance) + assert result == {"name": "test"} + + # Test with dict containing class + result = _normalize_data({"schema": TestClass, "count": 5}) + assert result == {"schema": "", "count": 5} From 18beca66cbad26682dc01270bd95a43f01788f0d Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Tue, 25 Nov 2025 09:38:51 +0100 Subject: [PATCH 2/4] lint From 9d9c1bc749cbf70f1e9541d00a7497e925a13a80 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Tue, 25 Nov 2025 09:40:24 +0100 Subject: [PATCH 3/4] lint --- tests/utils/test_general.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/utils/test_general.py b/tests/utils/test_general.py index a2846f4ddf..04e82b8c5c 100644 --- a/tests/utils/test_general.py +++ b/tests/utils/test_general.py @@ -626,24 +626,25 @@ def test_strip_string(input, max_length, result): def test_normalize_data_with_pydantic_class(): """Test that _normalize_data handles Pydantic model classes""" + class TestClass: name: str = None def __init__(self, name: str): self.name = name - + def model_dump(self): return {"name": self.name} - + # Test with class (should NOT call model_dump()) result = _normalize_data(TestClass) assert result == "" - + # Test with instance (should call model_dump()) instance = TestClass(name="test") result = _normalize_data(instance) assert result == {"name": "test"} - + # Test with dict containing class result = _normalize_data({"schema": TestClass, "count": 5}) assert result == {"schema": "", "count": 5} From 88c5c55a5c80d01d6dd613dae0de3178cd421310 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Tue, 25 Nov 2025 09:42:31 +0100 Subject: [PATCH 4/4] more lint --- sentry_sdk/ai/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry_sdk/ai/utils.py b/sentry_sdk/ai/utils.py index cff738d679..9a1853110f 100644 --- a/sentry_sdk/ai/utils.py +++ b/sentry_sdk/ai/utils.py @@ -1,4 +1,4 @@ -import inspect +import inspect import json from collections import deque from typing import TYPE_CHECKING