From c5c7aaa0c1481a981b8ad799938583ed2a827e60 Mon Sep 17 00:00:00 2001 From: Ben Langfeld Date: Tue, 13 Oct 2026 10:17:59 -0300 Subject: [PATCH] Name the blocking field in the update path's enterprise licence error When an update to a team, key, organisation or project sets a field that needs a LiteLLM Enterprise licence, `_update_metadata_field` called `premium_user_check()` with no feature, so the 403 didn't say which field was responsible. Pass the field name, as `set_object_metadata_field` already does on the create path. Co-Authored-By: Claude Opus 5.5 --- litellm/proxy/management_endpoints/common_utils.py | 2 +- .../unit/proxy/management_endpoints/test_common_utils.py | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/litellm/proxy/management_endpoints/common_utils.py b/litellm/proxy/management_endpoints/common_utils.py index adf89c29279..48a2f22eb64 100644 --- a/litellm/proxy/management_endpoints/common_utils.py +++ b/litellm/proxy/management_endpoints/common_utils.py @@ -789,7 +789,7 @@ def _update_metadata_field(updated_kv: dict, field_name: str) -> None: # only for a truthy value. The falsy value is still persisted below so a # previously-set field can be cleared. if updated_kv.get(field_name): - premium_user_check() + premium_user_check(field_name) if field_name in updated_kv and updated_kv[field_name] is not None: # remove field from updated_kv diff --git a/tests/unit/proxy/management_endpoints/test_common_utils.py b/tests/unit/proxy/management_endpoints/test_common_utils.py index 21d017addca..88acd260b7e 100644 --- a/tests/unit/proxy/management_endpoints/test_common_utils.py +++ b/tests/unit/proxy/management_endpoints/test_common_utils.py @@ -1307,6 +1307,15 @@ class TestSetObjectMetadataFieldPremiumArg: mock_premium.assert_called_once_with("guardrails") +class TestUpdateMetadataFieldLicenseError: + def test_license_error_names_the_blocking_field(self): + with patch("litellm.proxy.proxy_server.premium_user", False): + with pytest.raises(HTTPException) as exc_info: + update_metadata_fields({"team_id": "t1", "guardrails": ["g1"]}) + assert exc_info.value.status_code == 403 + assert "guardrails" in exc_info.value.detail["error"] + + class TestUpdateMetadataFieldMove: def test_none_valued_field_is_not_moved_into_metadata(self): """A None value must leave the field untouched (guard requires non-None)."""