diff --git a/litellm/rust_bridge/runtime.py b/litellm/rust_bridge/runtime.py index 5c9edaf4bdf..b9ad9706ab4 100644 --- a/litellm/rust_bridge/runtime.py +++ b/litellm/rust_bridge/runtime.py @@ -5,7 +5,7 @@ from dataclasses import dataclass from enum import Enum from typing import Final, Generic, NoReturn, TypeAlias, TypeVar -from litellm.exceptions import APIError +from litellm.exceptions import APIError, InternalServerError from litellm.rust_bridge.bindings import native_exception_types NativeT = TypeVar("NativeT") @@ -142,6 +142,12 @@ def raise_upstream(error: BaseException, context: BridgeErrorContext) -> NoRetur message_value: Final = args[1] if len(args) > 1 else str(error) status: Final = status_value if isinstance(status_value, int) else 0 message: Final = message_value if isinstance(message_value, str) else str(message_value) + if status == 500: + raise InternalServerError( + message=f"litellm rust {context.route}: {message}", + llm_provider=context.provider, + model=context.model, + ) from error raise APIError( status_code=status or 500, message=f"litellm rust {context.route}: {message}", diff --git a/tests/test_litellm/rust_bridge/test_runtime.py b/tests/test_litellm/rust_bridge/test_runtime.py index b0fa510069b..5ea511f0414 100644 --- a/tests/test_litellm/rust_bridge/test_runtime.py +++ b/tests/test_litellm/rust_bridge/test_runtime.py @@ -4,7 +4,7 @@ from types import SimpleNamespace import pytest -from litellm.exceptions import APIError +from litellm.exceptions import APIError, InternalServerError from litellm.rust_bridge import bindings, runtime @@ -64,6 +64,22 @@ def test_invoke_translates_upstream_without_fallback() -> None: assert caught.value.status_code == 429 +def test_invoke_translates_internal_server_error_without_fallback() -> None: + def fail() -> object: + raise RustUpstreamError(500, "provider unavailable") + + with pytest.raises(InternalServerError, match="provider unavailable") as caught: + runtime.invoke( + native_call=fail, + fallback=lambda: pytest.fail("fallback must not run"), + adapt=str, + mode=runtime.FallbackMode.PYTHON, + context=context(), + ) + + assert caught.value.status_code == 500 + + @pytest.mark.asyncio async def test_ainvoke_handles_native_success() -> None: async def native() -> int: diff --git a/tests/test_litellm_rust/test_integrations.py b/tests/test_litellm_rust/test_integrations.py index 4f9447bcb6f..2e919e1974a 100644 --- a/tests/test_litellm_rust/test_integrations.py +++ b/tests/test_litellm_rust/test_integrations.py @@ -62,14 +62,7 @@ async def test_generic_api_logger_exports_success_over_http(route: Route, provid "route", ( OCR_ASYNC, - pytest.param( - MESSAGES_ROUTE, - marks=pytest.mark.xfail( - strict=True, - raises=pytest.fail.Exception, - reason="Native Messages provider failure raises TypeError and falls back to a second Python request", - ), - ), + MESSAGES_ROUTE, ), ids=route_id, ) diff --git a/tests/test_litellm_rust/test_messages_callbacks.py b/tests/test_litellm_rust/test_messages_callbacks.py index d6644e27fdf..4e1abc77a5c 100644 --- a/tests/test_litellm_rust/test_messages_callbacks.py +++ b/tests/test_litellm_rust/test_messages_callbacks.py @@ -1,6 +1,5 @@ import asyncio import copy -import json import threading from typing import Final @@ -171,7 +170,6 @@ async def test_messages_logging_drain_waits_for_suspended_callback(messages_serv @pytest.mark.asyncio -@pytest.mark.xfail(strict=True, reason="accepted native Messages errors are replayed through the Python transport") async def test_messages_failure_callbacks_receive_original_provider_error(messages_server: RecordingServer) -> None: messages_server.default_response = ResponseSpec(body={"error": {"message": "provider unavailable"}}, status=500) messages_server.expected_requests = None