fix(exceptions): keep internal_server_error as the public type of an upstream 500

PR #40243 started carrying the upstream error body on InternalServerError so the Responses response.failed event can report the provider's code and message, and openai's APIError.__init__ took the body's type along with it. The proxy then answered an OpenAI-compatible upstream 500 with type server_error while a 502 and a 503 kept internal_server_error, and the integration contract in test_observed_routing.py went red. Pin the type the way RateLimitError pins throttling_error, keeping the body.
This commit is contained in:
mateo-berri 2026-09-18 22:28:58 -07:00
parent faed57f92c
commit ddac683ec6
3 changed files with 23 additions and 2 deletions

View file

@ -787,6 +787,7 @@ class InternalServerError(openai.InternalServerError):
super().__init__(
self.message, response=self.response, body=body
) # Call the base class constructor with the parameters it needs
self.type = "internal_server_error"
def __str__(self):
_message = self.message

View file

@ -1438,9 +1438,12 @@ def test_openai_compatible_vendor_400_keeps_body_but_not_headers():
@pytest.mark.parametrize(
("status_code", "mapped_class"), [(429, litellm.RateLimitError), (500, litellm.InternalServerError)]
("status_code", "mapped_class", "reported_type"),
[(429, litellm.RateLimitError, "throttling_error"), (500, litellm.InternalServerError, "internal_server_error")],
)
def test_openai_429_and_500_keep_body(status_code: int, mapped_class: type[openai.APIError]):
def test_openai_429_and_500_keep_body_but_report_litellm_type(
status_code: int, mapped_class: type[openai.APIError], reported_type: str
):
with pytest.raises(mapped_class) as exc_info:
exception_type(
model="gpt-5.4-mini",
@ -1458,6 +1461,7 @@ def test_openai_429_and_500_keep_body(status_code: int, mapped_class: type[opena
"code": str(status_code),
"message": "upstream cannot complete this response",
}
assert exc_info.value.type == reported_type
def test_litellm_proxy_repeated_response_header_keeps_each_value():

View file

@ -147,6 +147,22 @@ def test_a_status_carried_by_an_exception_drives_the_type_it_reports():
assert openai_error_type(exc, error_status_code(exc, 400)) == "permission_error"
def test_an_upstream_5xx_body_does_not_relabel_the_internal_server_error():
"""The upstream body rides along on the exception for the Responses ``response.failed``
event, but a 500 keeps answering the proxy's own ``internal_server_error`` label."""
from litellm.exceptions import InternalServerError
carried = InternalServerError(
message="Controlled provider failure",
model="gpt-5.4-mini",
llm_provider="openai",
body={"message": "Controlled provider failure", "type": "server_error", "code": "500"},
)
assert carried.body == {"message": "Controlled provider failure", "type": "server_error", "code": "500"}
assert openai_error_type(carried, error_status_code(carried, 400)) == "internal_server_error"
def test_a_stringified_none_type_or_param_is_treated_as_absent():
from litellm.exceptions import BadRequestError