From 2c2a6dd3f206ca3999bb5f128ae87065e81d2a9a Mon Sep 17 00:00:00 2001 From: david-koh Date: Wed, 14 Oct 2026 09:54:56 +0900 Subject: [PATCH 1/3] fix(proxy): hide project creation database errors --- .../management_endpoints/project_endpoints.py | 11 ++++++++++- .../test_project_endpoints_prisma.py | 17 +++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/enterprise/litellm_enterprise/proxy/management_endpoints/project_endpoints.py b/enterprise/litellm_enterprise/proxy/management_endpoints/project_endpoints.py index 154a60f1cd1..213e2996210 100644 --- a/enterprise/litellm_enterprise/proxy/management_endpoints/project_endpoints.py +++ b/enterprise/litellm_enterprise/proxy/management_endpoints/project_endpoints.py @@ -678,7 +678,16 @@ async def new_project( verbose_proxy_logger.exception( "litellm.proxy.management_endpoints.project_endpoints.new_project(): Exception occured - {}".format(str(e)) ) - raise handle_exception_on_proxy(e) + proxy_exception: Final[ProxyException] = handle_exception_on_proxy(e) + if proxy_exception.code == "500": + raise ProxyException( + message="Internal server error", + type="internal_server_error", + param=None, + code=500, + headers=proxy_exception.headers, + ) from e + raise proxy_exception @router.post( diff --git a/tests/unit/enterprise/proxy/management_endpoints/test_project_endpoints_prisma.py b/tests/unit/enterprise/proxy/management_endpoints/test_project_endpoints_prisma.py index 2a37ed2ed1f..887892b984b 100644 --- a/tests/unit/enterprise/proxy/management_endpoints/test_project_endpoints_prisma.py +++ b/tests/unit/enterprise/proxy/management_endpoints/test_project_endpoints_prisma.py @@ -1241,6 +1241,23 @@ async def test_new_project_flag_on_missing_rpm_tpm_returns_400(monkeypatch): assert "rpm/tpm quota" in str(exc_info.value) +@pytest.mark.asyncio +async def test_new_project_does_not_expose_database_errors(monkeypatch): + internal_detail = "db-internal-marker" + mock_prisma_client = mock.MagicMock() + mock_prisma_client.db.litellm_teamtable.find_unique = mock.AsyncMock(side_effect=RuntimeError(internal_detail)) + monkeypatch.setattr(litellm.proxy.proxy_server, "prisma_client", mock_prisma_client) + monkeypatch.setattr(litellm.proxy.proxy_server, "premium_user", True) + monkeypatch.setattr(litellm.proxy.proxy_server, "general_settings", {}) + + with pytest.raises(ProxyException) as exc_info: + await _run_new_project(NewProjectRequest(team_id="test-team")) + + assert exc_info.value.code == "500" + assert exc_info.value.message + assert internal_detail not in exc_info.value.message + + def _project_update_mocks(monkeypatch, stored_metadata: dict) -> mock.MagicMock: existing_row = mock.MagicMock( team_id=None, budget_id=None, object_permission_id=None, metadata=stored_metadata From 392a7a7a9a3299c2a91054ec647001f1852189e8 Mon Sep 17 00:00:00 2001 From: david-koh Date: Wed, 14 Oct 2026 10:04:00 +0900 Subject: [PATCH 2/3] test(proxy): preserve project creation license errors --- .../test_project_endpoints_prisma.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/unit/enterprise/proxy/management_endpoints/test_project_endpoints_prisma.py b/tests/unit/enterprise/proxy/management_endpoints/test_project_endpoints_prisma.py index 887892b984b..fc2fc8c1f49 100644 --- a/tests/unit/enterprise/proxy/management_endpoints/test_project_endpoints_prisma.py +++ b/tests/unit/enterprise/proxy/management_endpoints/test_project_endpoints_prisma.py @@ -1258,6 +1258,17 @@ async def test_new_project_does_not_expose_database_errors(monkeypatch): assert internal_detail not in exc_info.value.message +@pytest.mark.asyncio +async def test_new_project_keeps_license_error(monkeypatch): + monkeypatch.setattr(litellm.proxy.proxy_server, "premium_user", False) + + with pytest.raises(ProxyException) as exc_info: + await _run_new_project(NewProjectRequest(team_id="test-team")) + + assert exc_info.value.code == "403" + assert "enterprise feature" in exc_info.value.message + + def _project_update_mocks(monkeypatch, stored_metadata: dict) -> mock.MagicMock: existing_row = mock.MagicMock( team_id=None, budget_id=None, object_permission_id=None, metadata=stored_metadata From 4bdb2a7f20721a61a69696e0375e2eef7b918669 Mon Sep 17 00:00:00 2001 From: david-koh Date: Fri, 6 Nov 2026 10:45:58 +0900 Subject: [PATCH 3/3] test(proxy): keep quota configuration errors in server logs --- .../management_endpoints/test_project_endpoints_prisma.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/unit/enterprise/proxy/management_endpoints/test_project_endpoints_prisma.py b/tests/unit/enterprise/proxy/management_endpoints/test_project_endpoints_prisma.py index fc2fc8c1f49..5aeba34e073 100644 --- a/tests/unit/enterprise/proxy/management_endpoints/test_project_endpoints_prisma.py +++ b/tests/unit/enterprise/proxy/management_endpoints/test_project_endpoints_prisma.py @@ -2132,7 +2132,9 @@ async def test_new_project_quota_policy_reads_providers_from_router_deployments( @pytest.mark.asyncio -async def test_new_project_rejects_malformed_quota_setting_instead_of_skipping_it(monkeypatch: pytest.MonkeyPatch): +async def test_new_project_rejects_malformed_quota_setting_instead_of_skipping_it( + monkeypatch: pytest.MonkeyPatch, caplog: pytest.LogCaptureFixture +): _enforced_new_project_mocks( monkeypatch, team_models=["runway-gen4-turbo"], @@ -2144,7 +2146,8 @@ async def test_new_project_rejects_malformed_quota_setting_instead_of_skipping_i await _run_new_project(NewProjectRequest(team_id="test-team", models=["runway-gen4-turbo"])) assert exc_info.value.code == "500" - assert "general_settings.enforce_project_model_quota is invalid" in str(exc_info.value.message) + assert exc_info.value.message == "Internal server error" + assert "general_settings.enforce_project_model_quota is invalid" in caplog.text @pytest.mark.asyncio