diff --git a/litellm/router.py b/litellm/router.py index f72f41313a0..6f1f5696847 100644 --- a/litellm/router.py +++ b/litellm/router.py @@ -7467,7 +7467,7 @@ class Router: ) -> tuple[str, ...]: failed_deployment_id: Final[str | None] = getattr(exception, "failed_deployment_id", None) status_code: Final = getattr(exception, "status_code", None) - if not failed_deployment_id or status_code is None: + if not failed_deployment_id or not isinstance(status_code, int): return () if litellm._should_retry(status_code): # pyright: ignore[reportPrivateUsage] # as in should_retry_this_error return () diff --git a/tests/test_litellm/test_router.py b/tests/test_litellm/test_router.py index 12c1516837a..4bf75ad408c 100644 --- a/tests/test_litellm/test_router.py +++ b/tests/test_litellm/test_router.py @@ -13234,6 +13234,33 @@ async def test_router_retry_policy_400_retries_on_sibling_deployment( assert response._hidden_params["additional_headers"]["x-litellm-attempted-retries"] == 1 +@pytest.mark.parametrize( + "status_code,failed_deployment_id,already_skipped,healthy_deployment_ids,expected", + [ + (400, "rejecting", None, ["rejecting", "accepting"], ("rejecting",)), + (403, "rejecting", None, ["rejecting", "accepting"], ("rejecting",)), + (400, "second", ("first",), ["first", "second", "third"], ("first", "second")), + (429, "rejecting", None, ["rejecting", "accepting"], ()), + (503, "rejecting", None, ["rejecting", "accepting"], ()), + (400, "rejecting", None, ["rejecting"], ()), + (400, None, None, ["rejecting", "accepting"], ()), + (None, "rejecting", None, ["rejecting", "accepting"], ()), + ("400", "rejecting", None, ["rejecting", "accepting"], ()), + ], +) +def test_router_deployment_ids_to_skip_on_retry( + status_code, failed_deployment_id, already_skipped, healthy_deployment_ids, expected +): + exception = Exception("upstream refused this request") + exception.status_code = status_code + exception.failed_deployment_id = failed_deployment_id + healthy_deployments = [{"model_info": {"id": deployment_id}} for deployment_id in healthy_deployment_ids] + + assert ( + litellm.Router._deployment_ids_to_skip_on_retry(exception, already_skipped, healthy_deployments) == expected + ) + + def _make_failure_logging_obj(): return LiteLLMLogging( model="gpt-5.6",