fix(responses): surface upstream error status on get instead of 500 (#32287)

This commit is contained in:
Mateo Wang 2026-07-06 22:45:25 -07:00 • committed by GitHub
parent f8606b8b03
commit 7d6a080d3f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 125 additions and 3 deletions

View file

@ -1944,7 +1944,7 @@ def _map_azure_exception(
response=getattr(original_exception, "response", None),
body=getattr(original_exception, "body", None),
)
elif "invalid_request_error" in error_str:
elif "invalid_request_error" in error_str and getattr(original_exception, "status_code", None) in (None, 400):
raise BadRequestError(
message=f"AzureException BadRequestError - {message}",
llm_provider="azure",
@ -1986,6 +1986,14 @@ def _map_azure_exception(
litellm_debug_info=extra_information,
response=getattr(original_exception, "response", None),
)
elif original_exception.status_code == 404:
raise NotFoundError(
message=f"AzureException NotFoundError - {message}",
llm_provider="azure",
model=model,
litellm_debug_info=extra_information,
response=getattr(original_exception, "response", None),
)
elif original_exception.status_code == 408:
raise Timeout(
message=f"AzureException Timeout - {message}",

View file

@ -2912,6 +2912,7 @@ class BaseLLMHTTPHandler:
try:
response = sync_httpx_client.get(url=url, headers=headers, params=data)
response.raise_for_status()
except Exception as e:
raise self._handle_error(
e=e,
@ -2983,9 +2984,9 @@ class BaseLLMHTTPHandler:
try:
response = await async_httpx_client.get(url=url, headers=headers, params=data)
response.raise_for_status()
except Exception as e:
verbose_logger.exception(f"Error retrieving response: {e}")
verbose_logger.debug(f"Error retrieving response: {e}")
raise self._handle_error(
e=e,
provider_config=responses_api_provider_config,
@ -3076,6 +3077,7 @@ class BaseLLMHTTPHandler:
try:
response = sync_httpx_client.get(url=url, headers=headers, params=params)
response.raise_for_status()
except Exception as e:
raise self._handle_error(e=e, provider_config=responses_api_provider_config)
@ -3149,6 +3151,7 @@ class BaseLLMHTTPHandler:
try:
response = await async_httpx_client.get(url=url, headers=headers, params=params)
response.raise_for_status()
except Exception as e:
raise self._handle_error(e=e, provider_config=responses_api_provider_config)

View file

@ -649,3 +649,22 @@ def test_upstream_4xx_without_model_maps_to_bad_request():
assert excinfo.value.status_code == 400
assert "Cannot cancel a synchronous response." in excinfo.value.message
def test_azure_404_with_invalid_request_error_type_maps_to_not_found():
from litellm.llms.base_llm.chat.transformation import BaseLLMException
original_exception = BaseLLMException(
status_code=404,
message='{"error": {"message": "Response with id \'resp_abc\' not found.", "type": "invalid_request_error"}}',
)
with pytest.raises(litellm.NotFoundError) as excinfo:
exception_type(
model=None,
original_exception=original_exception,
custom_llm_provider="azure",
)
assert excinfo.value.status_code == 404
assert "Response with id 'resp_abc' not found." in excinfo.value.message

View file

@ -1745,3 +1745,95 @@ def test_sync_retrieve_file_content_raises_on_http_error():
)
assert exc_info.value.status_code == 404
_UPSTREAM_NOT_FOUND_BODY = {
"error": {
"message": "Response with id 'resp_abc' not found.",
"type": "invalid_request_error",
"param": None,
"code": None,
}
}
def _async_handler_returning(status_code: int, body: dict) -> AsyncHTTPHandler:
handler = AsyncHTTPHandler()
handler.client = httpx.AsyncClient(
transport=httpx.MockTransport(lambda request: httpx.Response(status_code, json=body))
)
return handler
def _sync_handler_returning(status_code: int, body: dict) -> HTTPHandler:
handler = HTTPHandler()
handler.client = httpx.Client(transport=httpx.MockTransport(lambda request: httpx.Response(status_code, json=body)))
return handler
@pytest.mark.asyncio
async def test_aget_responses_surfaces_upstream_error_status_instead_of_500():
client = _async_handler_returning(404, _UPSTREAM_NOT_FOUND_BODY)
with pytest.raises(litellm.NotFoundError) as excinfo:
await litellm.aget_responses(
response_id="resp_abc",
custom_llm_provider="azure",
api_base="https://test.openai.azure.com",
api_key="test-key",
api_version="2025-03-01-preview",
client=client,
)
assert excinfo.value.status_code == 404
assert "Response with id 'resp_abc' not found." in excinfo.value.message
def test_get_responses_surfaces_upstream_error_status_instead_of_500():
client = _sync_handler_returning(404, _UPSTREAM_NOT_FOUND_BODY)
with pytest.raises(litellm.NotFoundError) as excinfo:
litellm.get_responses(
response_id="resp_abc",
custom_llm_provider="azure",
api_base="https://test.openai.azure.com",
api_key="test-key",
api_version="2025-03-01-preview",
client=client,
)
assert excinfo.value.status_code == 404
assert "Response with id 'resp_abc' not found." in excinfo.value.message
def test_list_input_items_surfaces_upstream_error_status():
client = _sync_handler_returning(404, _UPSTREAM_NOT_FOUND_BODY)
with pytest.raises(litellm.NotFoundError) as excinfo:
litellm.list_input_items(
response_id="resp_abc",
custom_llm_provider="azure",
api_base="https://test.openai.azure.com",
api_key="test-key",
api_version="2025-03-01-preview",
client=client,
)
assert excinfo.value.status_code == 404
@pytest.mark.asyncio
async def test_alist_input_items_surfaces_upstream_error_status():
client = _async_handler_returning(404, _UPSTREAM_NOT_FOUND_BODY)
with pytest.raises(litellm.NotFoundError) as excinfo:
await litellm.alist_input_items(
response_id="resp_abc",
custom_llm_provider="azure",
api_base="https://test.openai.azure.com",
api_key="test-key",
api_version="2025-03-01-preview",
client=client,
)
assert excinfo.value.status_code == 404