diff --git a/litellm/litellm_core_utils/safe_json_dumps.py b/litellm/litellm_core_utils/safe_json_dumps.py index 63242a580e7..6d3a7d5feaf 100644 --- a/litellm/litellm_core_utils/safe_json_dumps.py +++ b/litellm/litellm_core_utils/safe_json_dumps.py @@ -66,7 +66,10 @@ def safe_json_structure( seen.remove(id(obj)) return result elif isinstance(obj, set): - result = sorted([_serialize(item, seen, depth + 1, key) for item in obj]) + result = sorted( + [_serialize(item, seen, depth + 1, key) for item in obj], + key=lambda item: json.dumps(item, sort_keys=True, default=str), + ) seen.remove(id(obj)) return result elif isinstance(obj, BaseModel): diff --git a/tests/unit/litellm_core_utils/test_safe_json_dumps.py b/tests/unit/litellm_core_utils/test_safe_json_dumps.py index 1f2664f33cb..35e8fc1b4b0 100644 --- a/tests/unit/litellm_core_utils/test_safe_json_dumps.py +++ b/tests/unit/litellm_core_utils/test_safe_json_dumps.py @@ -64,6 +64,14 @@ def test_complex_types(): assert result["tuple"] == [4, 5, 6] # Tuples are converted to lists +def test_set_with_mixed_types(): + data = {"metadata": {"labels": {"beta", 7, None}}} + + result = json.loads(safe_dumps(data)) + + assert result["metadata"]["labels"] == ["beta", 7, None] + + def test_unserializable_object(): # Test handling of unserializable objects class TestClass: