From 8f40567024554a8a8a6e44bbb81232a42326896b Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Fri, 10 Jul 2026 16:55:35 +0000 Subject: [PATCH] fix: constrain insufficient quota mapping --- .../exception_mapping_utils.py | 5 ++++- .../test_exception_mapping_utils.py | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/litellm/litellm_core_utils/exception_mapping_utils.py b/litellm/litellm_core_utils/exception_mapping_utils.py index a3e2b135e96..210163c22e5 100644 --- a/litellm/litellm_core_utils/exception_mapping_utils.py +++ b/litellm/litellm_core_utils/exception_mapping_utils.py @@ -250,6 +250,7 @@ class _ProviderHTTPException(Protocol): @runtime_checkable class _ProviderQuotaException(Protocol): + status_code: int body: object response: httpx.Response @@ -257,6 +258,8 @@ class _ProviderQuotaException(Protocol): def _get_insufficient_quota_response(original_exception: object) -> Optional[httpx.Response]: if not isinstance(original_exception, _ProviderQuotaException): return None + if original_exception.status_code != 429: + return None body = original_exception.body if not isinstance(body, Mapping): return None @@ -301,7 +304,7 @@ def _map_openai_exception( insufficient_quota_response = _get_insufficient_quota_response(original_exception) if insufficient_quota_response is not None: raise InsufficientQuotaError( - message=f"InsufficientQuotaError: {exception_provider} - {message}", + message=f"{exception_provider} - {message}", model=model, llm_provider=custom_llm_provider, response=insufficient_quota_response, diff --git a/tests/test_litellm/litellm_core_utils/test_exception_mapping_utils.py b/tests/test_litellm/litellm_core_utils/test_exception_mapping_utils.py index 25c07926be3..678adcb18cf 100644 --- a/tests/test_litellm/litellm_core_utils/test_exception_mapping_utils.py +++ b/tests/test_litellm/litellm_core_utils/test_exception_mapping_utils.py @@ -230,6 +230,7 @@ def test_openai_insufficient_quota_maps_to_distinct_rate_limit_subtype(body): assert isinstance(exc_info.value, litellm.RateLimitError) assert exc_info.value.code == "insufficient_quota" assert exc_info.value.type == "insufficient_quota" + assert str(exc_info.value).count("InsufficientQuotaError") == 1 assert litellm.InsufficientQuotaError in litellm.LITELLM_EXCEPTION_TYPES @@ -265,6 +266,24 @@ def test_openai_transient_429_remains_rate_limit_error(body): assert exc_info.value.type == "throttling_error" +def test_openai_non_429_insufficient_quota_body_is_not_quota_error(): + original_exception = OpenAIError( + status_code=403, + message="Forbidden", + headers={}, + body={"error": {"code": "insufficient_quota"}}, + ) + + with pytest.raises(litellm.APIError) as exc_info: + exception_type( + model="gpt-5.5", + original_exception=original_exception, + custom_llm_provider="openai", + ) + + assert type(exc_info.value) is litellm.APIError + + gemini_context_window_test_cases = [ # Gemini 2.0 Flash format (includes input token count in message) (