fix(exceptions): keep repeated litellm_proxy response headers on the rebuilt response

httpx.Headers.items() comma-joins repeated header names, so the rebuilt
response iterates multi_items() and keeps every value, matching what the
raw openai client exposes on e.response.headers
This commit is contained in:
mateo-berri 2026-09-14 22:59:40 -07:00
parent 62b2b36ce9
commit 9fb94ea761
2 changed files with 18 additions and 2 deletions

View file

@ -259,9 +259,10 @@ def _litellm_proxy_response(
headers: Final = getattr(original_exception, "headers", None)
if not isinstance(headers, Mapping) or not headers:
return response
pairs: Final = headers.multi_items() if isinstance(headers, httpx.Headers) else headers.items()
return httpx.Response(
status_code=response.status_code,
headers={str(k): str(v) for k, v in headers.items()},
headers=[(str(k), str(v)) for k, v in pairs],
request=getattr(original_exception, "request", None),
)

View file

@ -1373,7 +1373,7 @@ _GUARDRAIL_BLOCK_ERROR = {
def _openai_handler_error(
error_type: str,
headers: dict[str, str],
headers: dict[str, str] | list[tuple[str, str]],
status_code: int = 400,
message: str = _GUARDRAIL_BLOCK_ERROR["message"],
) -> OpenAIError:
@ -1435,3 +1435,18 @@ def test_openai_compatible_vendor_400_keeps_body_but_not_headers():
assert exc_info.value.body["type"] == "vendor_specific_error"
assert not exc_info.value.response.headers
def test_litellm_proxy_repeated_response_header_keeps_each_value():
repeated = [("x-litellm-call-id", "call-guardrail"), ("set-cookie", "a=1"), ("set-cookie", "b=2")]
with pytest.raises(litellm.BadRequestError) as exc_info:
exception_type(
model="claude-haiku-4-5",
original_exception=_openai_handler_error("None", repeated),
custom_llm_provider="litellm_proxy",
completion_kwargs={},
extra_kwargs={},
)
assert exc_info.value.response.headers.multi_items() == repeated