mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-11 03:38:38 +00:00
Merge pull request #11455 from colesmcintosh/429-fireworks-mapping
Fix Fireworks AI rate limit exception mapping - detect "rate limit" text in error messages
This commit is contained in:
commit
1ceb9f9621
2 changed files with 128 additions and 2 deletions
|
|
@ -24,6 +24,28 @@ from ..exceptions import (
|
|||
)
|
||||
|
||||
|
||||
class ExceptionCheckers:
|
||||
"""
|
||||
Helper class for checking various error conditions in exception strings.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def is_error_str_rate_limit(error_str: str) -> bool:
|
||||
"""
|
||||
Check if an error string indicates a rate limit error.
|
||||
|
||||
Args:
|
||||
error_str: The error string to check
|
||||
|
||||
Returns:
|
||||
True if the error indicates a rate limit, False otherwise
|
||||
"""
|
||||
if not isinstance(error_str, str):
|
||||
return False
|
||||
|
||||
return "429" in error_str or "rate limit" in error_str.lower()
|
||||
|
||||
|
||||
def get_error_message(error_obj) -> Optional[str]:
|
||||
"""
|
||||
OpenAI Returns Error message that is nested, this extract the message
|
||||
|
|
@ -274,7 +296,7 @@ def exception_type( # type: ignore # noqa: PLR0915
|
|||
+ "Exception"
|
||||
)
|
||||
|
||||
if "429" in error_str:
|
||||
if ExceptionCheckers.is_error_str_rate_limit(error_str):
|
||||
exception_mapping_worked = True
|
||||
raise RateLimitError(
|
||||
message=f"RateLimitError: {exception_provider} - {message}",
|
||||
|
|
@ -451,6 +473,15 @@ def exception_type( # type: ignore # noqa: PLR0915
|
|||
response=getattr(original_exception, "response", None),
|
||||
litellm_debug_info=extra_information,
|
||||
)
|
||||
elif original_exception.status_code == 500:
|
||||
exception_mapping_worked = True
|
||||
raise InternalServerError(
|
||||
message=f"InternalServerError: {exception_provider} - {message}",
|
||||
model=model,
|
||||
llm_provider=custom_llm_provider,
|
||||
response=getattr(original_exception, "response", None),
|
||||
litellm_debug_info=extra_information,
|
||||
)
|
||||
elif original_exception.status_code == 503:
|
||||
exception_mapping_worked = True
|
||||
raise ServiceUnavailableError(
|
||||
|
|
|
|||
|
|
@ -773,7 +773,7 @@ def test_litellm_predibase_exception():
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"provider", ["predibase", "vertex_ai_beta", "anthropic", "databricks", "watsonx"]
|
||||
"provider", ["predibase", "vertex_ai_beta", "anthropic", "databricks", "watsonx", "fireworks_ai"]
|
||||
)
|
||||
def test_exception_mapping(provider):
|
||||
"""
|
||||
|
|
@ -819,6 +819,98 @@ def test_exception_mapping(provider):
|
|||
pass
|
||||
|
||||
|
||||
def test_fireworks_ai_exception_mapping():
|
||||
"""
|
||||
Comprehensive test for Fireworks AI exception mapping, including:
|
||||
1. Standard 429 rate limit errors
|
||||
2. Text-based rate limit detection (the main issue fixed)
|
||||
3. Generic 400 errors that should NOT be rate limits
|
||||
4. ExceptionCheckers utility function
|
||||
|
||||
Related to: https://github.com/BerriAI/litellm/pull/11455
|
||||
Based on Fireworks AI documentation: https://docs.fireworks.ai/tools-sdks/python-client/api-reference
|
||||
"""
|
||||
import litellm
|
||||
from litellm.llms.fireworks_ai.common_utils import FireworksAIException
|
||||
from litellm.litellm_core_utils.exception_mapping_utils import ExceptionCheckers
|
||||
|
||||
# Test scenarios covering all important cases
|
||||
test_scenarios = [
|
||||
{
|
||||
"name": "Standard 429 rate limit with proper status code",
|
||||
"status_code": 429,
|
||||
"message": "Rate limit exceeded. Please try again in 60 seconds.",
|
||||
"expected_exception": litellm.RateLimitError,
|
||||
},
|
||||
{
|
||||
"name": "Status 400 with rate limit text (the main issue fixed)",
|
||||
"status_code": 400,
|
||||
"message": '{"error":{"object":"error","type":"invalid_request_error","message":"rate limit exceeded, please try again later"}}',
|
||||
"expected_exception": litellm.RateLimitError,
|
||||
},
|
||||
{
|
||||
"name": "Status 400 with generic invalid request (should NOT be rate limit)",
|
||||
"status_code": 400,
|
||||
"message": '{"error":{"type":"invalid_request_error","message":"Invalid parameter value"}}',
|
||||
"expected_exception": litellm.BadRequestError,
|
||||
},
|
||||
]
|
||||
|
||||
# Test each scenario
|
||||
for scenario in test_scenarios:
|
||||
mock_exception = FireworksAIException(
|
||||
status_code=scenario["status_code"],
|
||||
message=scenario["message"],
|
||||
headers={}
|
||||
)
|
||||
|
||||
try:
|
||||
response = litellm.completion(
|
||||
model="fireworks_ai/llama-v3p1-70b-instruct",
|
||||
messages=[{"role": "user", "content": "Hello"}],
|
||||
mock_response=mock_exception,
|
||||
)
|
||||
pytest.fail(f"Expected {scenario['expected_exception'].__name__} to be raised")
|
||||
except scenario["expected_exception"] as e:
|
||||
if scenario["expected_exception"] == litellm.RateLimitError:
|
||||
assert "rate limit" in str(e).lower() or "429" in str(e)
|
||||
except Exception as e:
|
||||
pytest.fail(f"Expected {scenario['expected_exception'].__name__} but got {type(e).__name__}: {e}")
|
||||
|
||||
# Test ExceptionCheckers.is_error_str_rate_limit() method directly
|
||||
|
||||
# Test cases that should return True (rate limit detected)
|
||||
rate_limit_strings = [
|
||||
"429 rate limit exceeded",
|
||||
"Rate limit exceeded, please try again later",
|
||||
"RATE LIMIT ERROR",
|
||||
"Error 429: rate limit",
|
||||
'{"error":{"type":"invalid_request_error","message":"rate limit exceeded, please try again later"}}',
|
||||
"HTTP 429 Too Many Requests",
|
||||
]
|
||||
|
||||
for error_str in rate_limit_strings:
|
||||
assert ExceptionCheckers.is_error_str_rate_limit(error_str), f"Should detect rate limit in: {error_str}"
|
||||
|
||||
# Test cases that should return False (not rate limit)
|
||||
non_rate_limit_strings = [
|
||||
"400 Bad Request",
|
||||
"Authentication failed",
|
||||
"Invalid model specified",
|
||||
"Context window exceeded",
|
||||
"Internal server error",
|
||||
"",
|
||||
"Some other error message",
|
||||
]
|
||||
|
||||
for error_str in non_rate_limit_strings:
|
||||
assert not ExceptionCheckers.is_error_str_rate_limit(error_str), f"Should NOT detect rate limit in: {error_str}"
|
||||
|
||||
# Test edge cases
|
||||
assert not ExceptionCheckers.is_error_str_rate_limit(None) # type: ignore
|
||||
assert not ExceptionCheckers.is_error_str_rate_limit(42) # type: ignore
|
||||
|
||||
|
||||
def test_anthropic_tool_calling_exception():
|
||||
"""
|
||||
Related - https://github.com/BerriAI/litellm/issues/4348
|
||||
|
|
@ -1285,3 +1377,6 @@ async def test_exception_bubbling_up(sync_mode, stream_mode, model):
|
|||
assert exc_info.value.code == "invalid_value"
|
||||
assert exc_info.value.param is not None
|
||||
assert exc_info.value.type == "invalid_request_error"
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue