mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-24 05:45:11 +00:00
fix(proxy): preserve HTTPException headers (retry-after) when converting to ProxyException
proxy_exception_from_http_exception() replaced the exception's own headers with only the caller-supplied dict, so a 429 raised by the rate limiter with retry-after lost that header on routes that convert HTTPException -> ProxyException (e.g. /v1/messages, unlike /v1/chat/completions where FastAPI serves HTTPException.headers directly). Merge exc.headers under the caller-supplied headers. Fixes #46630
This commit is contained in:
parent
bf56719f09
commit
5376a5c684
2 changed files with 20 additions and 1 deletions
|
|
@ -637,13 +637,16 @@ def proxy_exception_from_http_exception(exc: HTTPException, headers: dict[str, s
|
|||
existing_fields: Final = getattr(exc, "provider_specific_fields", None) or {}
|
||||
merged_fields: Final = {**existing_fields, **structured_fields} if structured_fields else (existing_fields or None)
|
||||
error_status: Final = error_status_code(exc, status.HTTP_400_BAD_REQUEST)
|
||||
# Preserve headers carried on the HTTPException itself (e.g. `retry-after`
|
||||
# set by the rate limiter on 429); caller-supplied headers win on conflict.
|
||||
merged_headers: Final = {**(exc.headers or {}), **headers}
|
||||
return ProxyException(
|
||||
message=message,
|
||||
type=openai_error_type(exc, error_status),
|
||||
param=openai_error_param(exc),
|
||||
code=error_status,
|
||||
provider_specific_fields=merged_fields,
|
||||
headers=headers,
|
||||
headers=merged_headers,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2355,6 +2355,22 @@ class TestCommonRequestProcessingHelpers:
|
|||
assert plain.code == "429"
|
||||
assert plain.provider_specific_fields is None
|
||||
|
||||
async def test_proxy_exception_from_http_exception_preserves_exc_headers(self):
|
||||
"""Headers carried on the HTTPException itself (e.g. `retry-after` set by
|
||||
the rate limiter on 429) must survive the conversion to ProxyException;
|
||||
caller-supplied headers win on conflict."""
|
||||
from litellm.proxy.common_request_processing import (
|
||||
proxy_exception_from_http_exception,
|
||||
)
|
||||
|
||||
exc = HTTPException(status_code=429, detail="slow down", headers={"retry-after": "60"})
|
||||
result = proxy_exception_from_http_exception(exc, {"x-litellm-call-id": "abc"})
|
||||
assert result.headers == {"retry-after": "60", "x-litellm-call-id": "abc"}
|
||||
|
||||
conflict = HTTPException(status_code=429, detail="slow down", headers={"retry-after": "60"})
|
||||
overridden = proxy_exception_from_http_exception(conflict, {"retry-after": "30"})
|
||||
assert overridden.headers == {"retry-after": "30"}
|
||||
|
||||
async def test_proxy_exception_from_route_error_helper(self) -> None:
|
||||
"""The shared route error -> ProxyException conversion keeps the status an exception
|
||||
carries, never the OpenAI SDK's ``code`` field (``None`` on most litellm exceptions)."""
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue