From d0dd9e299d3ae98bd61ce6f3f5b1f2c92625b0f4 Mon Sep 17 00:00:00 2001 From: Josh Hudson <313875020+hudsonwa@users.noreply.github.com> Date: Fri, 14 Aug 2026 16:45:02 +0800 Subject: [PATCH] fix(router): add NotFoundErrorRetries to RetryPolicy (#36896) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RetryPolicy had no field for NotFoundError, so 404s fell back to num_retries and were retried across the deployment pool. Each retry hit a fresh deployment, got another 404, and triggered an immediate cooldown — exhausting the pool and returning a 500 to the client. Add NotFoundErrorRetries: Optional[int] = None to RetryPolicy and wire it into get_num_retries_from_retry_policy(), letting operators pin 404s to 0 retries so they surface to the client immediately. --- litellm/router_utils/get_retry_from_policy.py | 3 +++ litellm/types/router.py | 1 + tests/router_unit_tests/test_router_helper_utils.py | 1 + 3 files changed, 5 insertions(+) diff --git a/litellm/router_utils/get_retry_from_policy.py b/litellm/router_utils/get_retry_from_policy.py index 7cf55e80e0c..ce6b6c7c122 100644 --- a/litellm/router_utils/get_retry_from_policy.py +++ b/litellm/router_utils/get_retry_from_policy.py @@ -8,6 +8,7 @@ from litellm.exceptions import ( AuthenticationError, BadRequestError, ContentPolicyViolationError, + NotFoundError, RateLimitError, Timeout, ) @@ -50,6 +51,8 @@ def get_num_retries_from_retry_policy( return retry_policy.ContentPolicyViolationErrorRetries if isinstance(exception, BadRequestError) and retry_policy.BadRequestErrorRetries is not None: return retry_policy.BadRequestErrorRetries + if isinstance(exception, NotFoundError) and retry_policy.NotFoundErrorRetries is not None: + return retry_policy.NotFoundErrorRetries def reset_retry_policy() -> RetryPolicy: diff --git a/litellm/types/router.py b/litellm/types/router.py index 217364c48b7..44985a28c66 100644 --- a/litellm/types/router.py +++ b/litellm/types/router.py @@ -100,6 +100,7 @@ class RetryPolicy(BaseModel): RateLimitErrorRetries: int | None = None ContentPolicyViolationErrorRetries: int | None = None InternalServerErrorRetries: int | None = None + NotFoundErrorRetries: int | None = None class UpdateRouterConfig(BaseModel): diff --git a/tests/router_unit_tests/test_router_helper_utils.py b/tests/router_unit_tests/test_router_helper_utils.py index c883890f5f6..0982fff7d85 100644 --- a/tests/router_unit_tests/test_router_helper_utils.py +++ b/tests/router_unit_tests/test_router_helper_utils.py @@ -1352,6 +1352,7 @@ def test_track_deployment_metrics(model_list): "ContentPolicyViolationError", 7, ), + (litellm.exceptions.NotFoundError, "NotFoundError", 0), ], ) def test_get_num_retries_from_retry_policy(