diff --git a/litellm/proxy/management_endpoints/key_management_endpoints.py b/litellm/proxy/management_endpoints/key_management_endpoints.py index d37dfe87ad5..c5f25f51599 100644 --- a/litellm/proxy/management_endpoints/key_management_endpoints.py +++ b/litellm/proxy/management_endpoints/key_management_endpoints.py @@ -4429,6 +4429,13 @@ async def info_key_fn( # default to using Auth token if no key is passed in key = key or user_api_key_dict.api_key + if not key: + raise ProxyException( + message="No key passed in. Pass ?key= or authenticate with a virtual key.", + type=ProxyErrorTypes.bad_request_error, + param="key", + code=status.HTTP_400_BAD_REQUEST, + ) hashed_key: str | None = key if key is not None: hashed_key = _hash_token_if_needed(token=key) diff --git a/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py b/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py index a5d2828dd9c..f9ca76aef44 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py +++ b/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py @@ -6598,6 +6598,22 @@ async def test_info_key_fn_unknown_key_still_404s(monkeypatch): assert exc_info.value.code == "404" +@pytest.mark.asyncio +async def test_info_key_fn_no_key_returns_400_not_500(monkeypatch): + """#43571: when both ?key= and auth api_key are None, return a clean 400 + instead of letting Prisma raise MissingRequiredValueError as a 500.""" + from litellm.proxy.management_endpoints.key_management_endpoints import info_key_fn + + mock_prisma_client = AsyncMock() + monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma_client) + + auth = UserAPIKeyAuth(user_role=LitellmUserRoles.PROXY_ADMIN, api_key=None) + with pytest.raises(ProxyException) as exc_info: + await info_key_fn(key=None, user_api_key_dict=auth) + assert exc_info.value.code == "400" + mock_prisma_client.db.litellm_verificationtoken.find_unique.assert_not_called() + + @pytest.mark.asyncio @pytest.mark.parametrize( ("blocked", "expires", "expected_status"),