fix(messages): state no headers for a native failure without wire headers

A failure the native path raises without an HTTP error response, such as an unreadable 200 body or a header value the client refuses to send, carries no wire headers, and Python logs none for it. The rebuilt response added a content-length from the error text
This commit is contained in:
narmstrong-berri 2026-11-06 15:12:39 +00:00
parent f254d57f38
commit 1adc411260
No known key found for this signature in database
2 changed files with 15 additions and 0 deletions

View file

@ -186,6 +186,8 @@ def _upstream_failure(
headers: Final = _UPSTREAM_HEADERS.validate_python(getattr(error, "headers", None))
except ValidationError:
return None
if not headers:
return status, text, headers
# Python's `MaskedHTTPStatusError` rebuilds the response from its decoded body without the
# wire's content-encoding and content-length, so httpx states a length only for a non-empty body.
rebuilt: Final = httpx.Response(

View file

@ -243,6 +243,19 @@ def test_upstream_failure_headers_match_the_python_clients_rebuilt_response(
assert dict(_get_response_headers(mapped) or {}) == expected
@pytest.mark.parametrize("status", [200, 500])
def test_upstream_failure_without_wire_headers_states_no_headers(status: int) -> None:
from litellm.litellm_core_utils.exception_mapping_utils import _get_response_headers
upstream: Final = ValueError(status, "not a messages response")
upstream.headers = [] # pyright: ignore[reportAttributeAccessIssue] # set by the native host
mapped: Final = messages_host.map_failure(upstream, {"model": _ADAPTIVE_OPUS}, "anthropic")
assert isinstance(mapped, Exception)
assert not dict(_get_response_headers(mapped) or {})
def test_a_late_rejection_tells_the_logger_the_resolved_call_first() -> None:
import datetime