diff --git a/litellm/litellm_core_utils/safe_json_dumps.py b/litellm/litellm_core_utils/safe_json_dumps.py index 5b99e8cba98..d9eb69ec41b 100644 --- a/litellm/litellm_core_utils/safe_json_dumps.py +++ b/litellm/litellm_core_utils/safe_json_dumps.py @@ -62,7 +62,10 @@ def safe_dumps( 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/test_litellm/litellm_core_utils/test_safe_json_dumps.py b/tests/test_litellm/litellm_core_utils/test_safe_json_dumps.py index 30385ba758d..d17358626c8 100644 --- a/tests/test_litellm/litellm_core_utils/test_safe_json_dumps.py +++ b/tests/test_litellm/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: