mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-15 23:31:29 +00:00
fix(team): don't log legitimate 403s at error level on /callback endpoints
Greptile flagged that ``disable_team_logging`` and ``get_team_callbacks`` re-wrap any ``HTTPException`` (including the 403 from the access guard) through a catch-all that logs at ``.error()`` before re-raising — so every legitimate access-denied response would pollute alerting dashboards as a "server error". Add explicit ``except HTTPException: raise`` and ``except ProxyException: raise`` branches before the catch-all (matching the pattern already used in ``add_team_callbacks``). 4xx now propagates quietly; only genuinely unexpected exceptions still hit the error-level log. Tests assert ``HTTPException`` is now the surfaced shape (instead of the previous ``ProxyException`` re-wrap). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
140628063c
commit
578846e57d
2 changed files with 21 additions and 25 deletions
|
|
@ -251,20 +251,18 @@ async def disable_team_logging(
|
|||
},
|
||||
}
|
||||
|
||||
except HTTPException:
|
||||
# Legitimate 4xx (e.g. 403 from the access guard, 404 for an
|
||||
# unknown team). Re-raise without the error-level log noise that
|
||||
# the catch-all branch below would produce.
|
||||
raise
|
||||
except ProxyException:
|
||||
raise
|
||||
except Exception as e:
|
||||
verbose_proxy_logger.error(
|
||||
f"litellm.proxy.proxy_server.disable_team_logging(): Exception occurred - {str(e)}"
|
||||
)
|
||||
verbose_proxy_logger.debug(traceback.format_exc())
|
||||
if isinstance(e, HTTPException):
|
||||
raise ProxyException(
|
||||
message=getattr(e, "detail", f"Internal Server Error({str(e)})"),
|
||||
type=ProxyErrorTypes.internal_server_error.value,
|
||||
param=getattr(e, "param", "None"),
|
||||
code=getattr(e, "status_code", status.HTTP_500_INTERNAL_SERVER_ERROR),
|
||||
)
|
||||
elif isinstance(e, ProxyException):
|
||||
raise e
|
||||
raise ProxyException(
|
||||
message="Internal Server Error, " + str(e),
|
||||
type=ProxyErrorTypes.internal_server_error.value,
|
||||
|
|
@ -349,6 +347,13 @@ async def get_team_callbacks(
|
|||
},
|
||||
}
|
||||
|
||||
except HTTPException:
|
||||
# Legitimate 4xx (e.g. 403 from the access guard) — re-raise
|
||||
# without the error-level log noise that the catch-all below
|
||||
# would produce.
|
||||
raise
|
||||
except ProxyException:
|
||||
raise
|
||||
except Exception as e:
|
||||
verbose_proxy_logger.error(
|
||||
"litellm.proxy.proxy_server.get_team_callbacks(): Exception occurred - {}".format(
|
||||
|
|
|
|||
|
|
@ -108,18 +108,16 @@ async def test_add_team_callbacks_rejects_unauthorized_caller(
|
|||
async def test_disable_team_logging_rejects_unauthorized_caller(
|
||||
patched_prisma, unauthorized_caller
|
||||
):
|
||||
# The endpoint catches HTTPException and re-wraps it as ProxyException
|
||||
# with the original status code preserved.
|
||||
from litellm.proxy._types import ProxyException
|
||||
|
||||
with pytest.raises((HTTPException, ProxyException)) as exc:
|
||||
# The HTTPException from the access guard now propagates directly
|
||||
# — the catch-all that previously re-wrapped (and logged at error
|
||||
# level) was narrowed so legitimate 4xx don't pollute alerting.
|
||||
with pytest.raises(HTTPException) as exc:
|
||||
await disable_team_logging(
|
||||
http_request=Mock(spec=Request),
|
||||
team_id="team-victim",
|
||||
user_api_key_dict=unauthorized_caller,
|
||||
)
|
||||
code = getattr(exc.value, "status_code", None) or getattr(exc.value, "code", None)
|
||||
assert int(code) == 403
|
||||
assert exc.value.status_code == 403
|
||||
patched_prisma.db.litellm_teamtable.update.assert_not_called()
|
||||
|
||||
|
||||
|
|
@ -127,20 +125,13 @@ async def test_disable_team_logging_rejects_unauthorized_caller(
|
|||
async def test_get_team_callbacks_rejects_unauthorized_caller(
|
||||
patched_prisma, unauthorized_caller
|
||||
):
|
||||
# The endpoint catches generic Exception and re-wraps as ProxyException;
|
||||
# an HTTPException raised by the access guard surfaces as a 403
|
||||
# ProxyException — both shapes are acceptable failure modes, what
|
||||
# matters is that the caller does NOT receive the team's callback data.
|
||||
from litellm.proxy._types import ProxyException
|
||||
|
||||
with pytest.raises((HTTPException, ProxyException)) as exc:
|
||||
with pytest.raises(HTTPException) as exc:
|
||||
await get_team_callbacks(
|
||||
http_request=Mock(spec=Request),
|
||||
team_id="team-victim",
|
||||
user_api_key_dict=unauthorized_caller,
|
||||
)
|
||||
code = getattr(exc.value, "status_code", None) or getattr(exc.value, "code", None)
|
||||
assert int(code) == 403
|
||||
assert exc.value.status_code == 403
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue