From 887d2f57f57000c92d7ee108a07c4d143df4126e Mon Sep 17 00:00:00 2001 From: mubashir1osmani Date: Tue, 23 Jun 2026 15:30:35 -0700 Subject: [PATCH] Revert "fix(proxy): json-encode team budget_limits on /team/new so Prisma accepts multi-window budgets" This reverts commit e47e902ce057d0dbb4e55cce250caa8a8b1d9b5d. --- .../management_endpoints/team_endpoints.py | 5 -- .../test_team_endpoints.py | 60 ------------------- 2 files changed, 65 deletions(-) diff --git a/litellm/proxy/management_endpoints/team_endpoints.py b/litellm/proxy/management_endpoints/team_endpoints.py index e90bcd5aa31..4d4d1ef2774 100644 --- a/litellm/proxy/management_endpoints/team_endpoints.py +++ b/litellm/proxy/management_endpoints/team_endpoints.py @@ -1268,11 +1268,6 @@ async def new_team( complete_team_data_dict = complete_team_data.model_dump(exclude_none=True) - if complete_team_data_dict.get("budget_limits") is not None: - complete_team_data_dict["budget_limits"] = json.dumps( - complete_team_data_dict["budget_limits"] - ) - # Serialize router_settings to JSON (matching key creation pattern) router_settings_value = getattr(data, "router_settings", None) router_settings_json = ( diff --git a/tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py b/tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py index c8d702416ef..b81807ee19e 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py +++ b/tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py @@ -461,66 +461,6 @@ async def test_new_team_with_object_permission(mock_db_client, mock_admin_auth): assert "object_permission" not in team_data -@pytest.mark.asyncio -async def test_new_team_serializes_multi_window_budget_limits( - mock_db_client, mock_admin_auth -): - """ - Regression test for LIT-3896: /team/new must json-encode budget_limits before - passing them to Prisma. The LiteLLM_TeamTable.budget_limits column is `Json?`, - and jsonify_team_object only stringifies dict values, so a raw Python list - reaches Prisma unencoded and the create call 500s. - """ - import json - - mock_db_client.jsonify_team_object = lambda db_data: db_data - mock_db_client.get_data = AsyncMock(return_value=None) - mock_db_client.update_data = AsyncMock(return_value=MagicMock()) - mock_db_client.db = MagicMock() - - mock_db_client.db.litellm_teamtable = MagicMock() - mock_db_client.db.litellm_teamtable.count = AsyncMock(return_value=0) - mock_db_client.db.litellm_teamtable.create = AsyncMock( - return_value=MagicMock(team_id="team-budget-windows") - ) - mock_db_client.db.litellm_teamtable.update = AsyncMock(return_value=MagicMock()) - mock_db_client.db.litellm_usertable = MagicMock() - mock_db_client.db.litellm_usertable.update = AsyncMock(return_value=MagicMock()) - - from fastapi import Request - - from litellm.models.team import BudgetLimitEntry - from litellm.proxy._types import NewTeamRequest - from litellm.proxy.management_endpoints.team_endpoints import new_team - - team_request = NewTeamRequest( - team_alias="multi-window-team", - budget_limits=[ - BudgetLimitEntry(budget_duration="1d", max_budget=10.0), - BudgetLimitEntry(budget_duration="30d", max_budget=100.0), - ], - ) - - dummy_request = MagicMock(spec=Request) - - await new_team( - data=team_request, - http_request=dummy_request, - user_api_key_dict=mock_admin_auth, - ) - - created_data = mock_db_client.db.litellm_teamtable.create.call_args.kwargs["data"] - - assert isinstance(created_data["budget_limits"], str) - - decoded = json.loads(created_data["budget_limits"]) - assert isinstance(decoded, list) - assert len(decoded) == 2 - assert {w["budget_duration"] for w in decoded} == {"1d", "30d"} - assert {w["max_budget"] for w in decoded} == {10.0, 100.0} - assert all(w.get("reset_at") for w in decoded) - - @pytest.mark.asyncio async def test_new_team_with_mcp_tool_permissions(mock_db_client, mock_admin_auth): """