From 239edc472a1e2a773654645163090b9d50f2932d Mon Sep 17 00:00:00 2001 From: michelligabriele Date: Fri, 13 Mar 2026 20:06:36 +0100 Subject: [PATCH] fix(ui): use sanitizeNumeric for team_member_budget in team edit form (#23505) * fix(gemini): preserve toolConfig on native generate_content (#23493) * fix(ui): use sanitizeNumeric for team_member_budget in team edit form The team edit form (TeamInfo.tsx) used Number() to convert the team_member_budget field value, which silently converts null/undefined/"" to 0. When an admin edits a team for any reason without touching the budget field, this sends team_member_budget=0 to the backend, creating a shared budget row with max_budget=0.0 that blocks all team members. Use sanitizeNumeric (already used for tpm_limit, rpm_limit, soft_budget in the same form) which correctly returns null for empty/null/undefined values, preventing accidental zero-budget creation. --------- Co-authored-by: Emerson Gomes --- .../test_team_endpoints.py | 59 +++++++++++++++++++ .../src/components/team/TeamInfo.tsx | 2 +- 2 files changed, 60 insertions(+), 1 deletion(-) 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 1aee1d49658..49e35ae2519 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py +++ b/tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py @@ -1385,6 +1385,65 @@ async def test_update_team_team_member_budget_not_passed_to_db(): ) +def test_should_create_budget_with_none_values(): + """Test that should_create_budget returns False when all values are None.""" + from litellm.proxy.management_endpoints.team_endpoints import ( + TeamMemberBudgetHandler, + ) + + assert TeamMemberBudgetHandler.should_create_budget() is False + assert ( + TeamMemberBudgetHandler.should_create_budget( + team_member_budget=None, + team_member_rpm_limit=None, + team_member_tpm_limit=None, + team_member_budget_duration=None, + ) + is False + ) + + +def test_should_create_budget_with_zero_budget(): + """Test that should_create_budget returns True for explicit 0 budget. + + 0 is a valid explicit budget (zero dollars allowed). The UI bug was + sending 0 when the user didn't set a value — that's fixed in the UI + by using sanitizeNumeric. The backend correctly treats 0 as intentional. + """ + from litellm.proxy.management_endpoints.team_endpoints import ( + TeamMemberBudgetHandler, + ) + + assert TeamMemberBudgetHandler.should_create_budget(team_member_budget=0) is True + assert ( + TeamMemberBudgetHandler.should_create_budget(team_member_budget=0.0) is True + ) + + +def test_should_create_budget_with_valid_values(): + """Test that should_create_budget returns True when any value is provided.""" + from litellm.proxy.management_endpoints.team_endpoints import ( + TeamMemberBudgetHandler, + ) + + assert ( + TeamMemberBudgetHandler.should_create_budget(team_member_budget=100.0) is True + ) + assert ( + TeamMemberBudgetHandler.should_create_budget(team_member_rpm_limit=50) is True + ) + assert ( + TeamMemberBudgetHandler.should_create_budget(team_member_tpm_limit=1000) + is True + ) + assert ( + TeamMemberBudgetHandler.should_create_budget( + team_member_budget_duration="30d" + ) + is True + ) + + def test_clean_team_member_fields(): """ Test that _clean_team_member_fields removes all team member fields from a dictionary. diff --git a/ui/litellm-dashboard/src/components/team/TeamInfo.tsx b/ui/litellm-dashboard/src/components/team/TeamInfo.tsx index d2ce79580da..64bd3fafd69 100644 --- a/ui/litellm-dashboard/src/components/team/TeamInfo.tsx +++ b/ui/litellm-dashboard/src/components/team/TeamInfo.tsx @@ -497,7 +497,7 @@ const TeamInfoView: React.FC = ({ updateData.team_member_budget_duration = values.team_member_budget_duration; if (values.team_member_budget !== undefined) { - updateData.team_member_budget = Number(values.team_member_budget); + updateData.team_member_budget = sanitizeNumeric(values.team_member_budget); } if (values.team_member_key_duration !== undefined) {