diff --git a/litellm/router_strategy/complexity_router/complexity_router.py b/litellm/router_strategy/complexity_router/complexity_router.py index d7bbf85d4fa..2c1097b7af3 100644 --- a/litellm/router_strategy/complexity_router/complexity_router.py +++ b/litellm/router_strategy/complexity_router/complexity_router.py @@ -880,7 +880,9 @@ class _ClassifierCircuitBreaker: def _is_classifier_timeout(exc: BaseException) -> bool: - if isinstance(exc, TimeoutError): + # asyncio.TimeoutError became an alias of the built-in TimeoutError in Python 3.11. + # LiteLLM still supports 3.10, where they are distinct exception classes. + if isinstance(exc, (TimeoutError, asyncio.TimeoutError)): return True from litellm.exceptions import Timeout as LiteLLMTimeout diff --git a/tests/test_litellm/router_strategy/test_complexity_router.py b/tests/test_litellm/router_strategy/test_complexity_router.py index 137fb128a57..130a6f5a488 100644 --- a/tests/test_litellm/router_strategy/test_complexity_router.py +++ b/tests/test_litellm/router_strategy/test_complexity_router.py @@ -26,6 +26,7 @@ from litellm.router_strategy.complexity_router.complexity_router import ( KeywordOverride, _built_in_prompt, _ClassifierCircuitBreaker, + _is_classifier_timeout, _matched_plan_mode_sentinel, classification_system_prompt, ) @@ -2196,6 +2197,9 @@ class TestLLMClassifier: breaker.record_failure(permit, is_timeout=False) assert breaker.acquire_permit() is not None + def test_asyncio_timeout_is_a_classifier_timeout_on_python_310(self): + assert _is_classifier_timeout(asyncio.TimeoutError()) is True + @pytest.mark.asyncio async def test_aclassify_classifier_cost_is_none_when_call_is_unpriced( self, llm_complexity_router, mock_router_instance