Merge pull request #9109 from BerriAI/litellm_dev_03_10_2025_p1_v2
Return `code`, `param` and `type` on openai bad request error
This commit is contained in:
commit
9610c844c7
@ -118,6 +118,7 @@ class BadRequestError(openai.BadRequestError): # type: ignore
|
||||
litellm_debug_info: Optional[str] = None,
|
||||
max_retries: Optional[int] = None,
|
||||
num_retries: Optional[int] = None,
|
||||
body: Optional[dict] = None,
|
||||
):
|
||||
self.status_code = 400
|
||||
self.message = "litellm.BadRequestError: {}".format(message)
|
||||
@ -133,7 +134,7 @@ class BadRequestError(openai.BadRequestError): # type: ignore
|
||||
self.max_retries = max_retries
|
||||
self.num_retries = num_retries
|
||||
super().__init__(
|
||||
self.message, response=response, body=None
|
||||
self.message, response=response, body=body
|
||||
) # Call the base class constructor with the parameters it needs
|
||||
|
||||
def __str__(self):
|
||||
|
||||
@ -331,6 +331,7 @@ def exception_type( # type: ignore # noqa: PLR0915
|
||||
model=model,
|
||||
response=getattr(original_exception, "response", None),
|
||||
litellm_debug_info=extra_information,
|
||||
body=getattr(original_exception, "body", None),
|
||||
)
|
||||
elif (
|
||||
"Web server is returning an unknown error" in error_str
|
||||
@ -421,6 +422,7 @@ def exception_type( # type: ignore # noqa: PLR0915
|
||||
llm_provider=custom_llm_provider,
|
||||
response=getattr(original_exception, "response", None),
|
||||
litellm_debug_info=extra_information,
|
||||
body=getattr(original_exception, "body", None),
|
||||
)
|
||||
elif original_exception.status_code == 429:
|
||||
exception_mapping_worked = True
|
||||
@ -1960,6 +1962,7 @@ def exception_type( # type: ignore # noqa: PLR0915
|
||||
model=model,
|
||||
litellm_debug_info=extra_information,
|
||||
response=getattr(original_exception, "response", None),
|
||||
body=getattr(original_exception, "body", None),
|
||||
)
|
||||
elif (
|
||||
"The api_key client option must be set either by passing api_key to the client or by setting"
|
||||
@ -1991,6 +1994,7 @@ def exception_type( # type: ignore # noqa: PLR0915
|
||||
model=model,
|
||||
litellm_debug_info=extra_information,
|
||||
response=getattr(original_exception, "response", None),
|
||||
body=getattr(original_exception, "body", None),
|
||||
)
|
||||
elif original_exception.status_code == 401:
|
||||
exception_mapping_worked = True
|
||||
|
||||
@ -540,10 +540,14 @@ class AzureChatCompletion(BaseLLM):
|
||||
status_code = getattr(e, "status_code", 500)
|
||||
error_headers = getattr(e, "headers", None)
|
||||
error_response = getattr(e, "response", None)
|
||||
error_body = getattr(e, "body", None)
|
||||
if error_headers is None and error_response:
|
||||
error_headers = getattr(error_response, "headers", None)
|
||||
raise AzureOpenAIError(
|
||||
status_code=status_code, message=str(e), headers=error_headers
|
||||
status_code=status_code,
|
||||
message=str(e),
|
||||
headers=error_headers,
|
||||
body=error_body,
|
||||
)
|
||||
|
||||
async def acompletion(
|
||||
@ -649,6 +653,7 @@ class AzureChatCompletion(BaseLLM):
|
||||
raise AzureOpenAIError(status_code=500, message=str(e))
|
||||
except Exception as e:
|
||||
message = getattr(e, "message", str(e))
|
||||
body = getattr(e, "body", None)
|
||||
## LOGGING
|
||||
logging_obj.post_call(
|
||||
input=data["messages"],
|
||||
@ -659,7 +664,7 @@ class AzureChatCompletion(BaseLLM):
|
||||
if hasattr(e, "status_code"):
|
||||
raise e
|
||||
else:
|
||||
raise AzureOpenAIError(status_code=500, message=message)
|
||||
raise AzureOpenAIError(status_code=500, message=message, body=body)
|
||||
|
||||
def streaming(
|
||||
self,
|
||||
@ -805,10 +810,14 @@ class AzureChatCompletion(BaseLLM):
|
||||
error_headers = getattr(e, "headers", None)
|
||||
error_response = getattr(e, "response", None)
|
||||
message = getattr(e, "message", str(e))
|
||||
error_body = getattr(e, "body", None)
|
||||
if error_headers is None and error_response:
|
||||
error_headers = getattr(error_response, "headers", None)
|
||||
raise AzureOpenAIError(
|
||||
status_code=status_code, message=message, headers=error_headers
|
||||
status_code=status_code,
|
||||
message=message,
|
||||
headers=error_headers,
|
||||
body=error_body,
|
||||
)
|
||||
|
||||
async def aembedding(
|
||||
|
||||
@ -17,6 +17,7 @@ class AzureOpenAIError(BaseLLMException):
|
||||
request: Optional[httpx.Request] = None,
|
||||
response: Optional[httpx.Response] = None,
|
||||
headers: Optional[Union[httpx.Headers, dict]] = None,
|
||||
body: Optional[dict] = None,
|
||||
):
|
||||
super().__init__(
|
||||
status_code=status_code,
|
||||
@ -24,6 +25,7 @@ class AzureOpenAIError(BaseLLMException):
|
||||
request=request,
|
||||
response=response,
|
||||
headers=headers,
|
||||
body=body,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@ -51,6 +51,7 @@ class BaseLLMException(Exception):
|
||||
headers: Optional[Union[dict, httpx.Headers]] = None,
|
||||
request: Optional[httpx.Request] = None,
|
||||
response: Optional[httpx.Response] = None,
|
||||
body: Optional[dict] = None,
|
||||
):
|
||||
self.status_code = status_code
|
||||
self.message: str = message
|
||||
@ -67,6 +68,7 @@ class BaseLLMException(Exception):
|
||||
self.response = httpx.Response(
|
||||
status_code=status_code, request=self.request
|
||||
)
|
||||
self.body = body
|
||||
super().__init__(
|
||||
self.message
|
||||
) # Call the base class constructor with the parameters it needs
|
||||
|
||||
@ -19,6 +19,7 @@ class OpenAIError(BaseLLMException):
|
||||
request: Optional[httpx.Request] = None,
|
||||
response: Optional[httpx.Response] = None,
|
||||
headers: Optional[Union[dict, httpx.Headers]] = None,
|
||||
body: Optional[dict] = None,
|
||||
):
|
||||
self.status_code = status_code
|
||||
self.message = message
|
||||
@ -39,6 +40,7 @@ class OpenAIError(BaseLLMException):
|
||||
headers=self.headers,
|
||||
request=self.request,
|
||||
response=self.response,
|
||||
body=body,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@ -732,10 +732,14 @@ class OpenAIChatCompletion(BaseLLM):
|
||||
error_headers = getattr(e, "headers", None)
|
||||
error_text = getattr(e, "text", str(e))
|
||||
error_response = getattr(e, "response", None)
|
||||
error_body = getattr(e, "body", None)
|
||||
if error_headers is None and error_response:
|
||||
error_headers = getattr(error_response, "headers", None)
|
||||
raise OpenAIError(
|
||||
status_code=status_code, message=error_text, headers=error_headers
|
||||
status_code=status_code,
|
||||
message=error_text,
|
||||
headers=error_headers,
|
||||
body=error_body,
|
||||
)
|
||||
|
||||
async def acompletion(
|
||||
@ -828,13 +832,17 @@ class OpenAIChatCompletion(BaseLLM):
|
||||
except Exception as e:
|
||||
exception_response = getattr(e, "response", None)
|
||||
status_code = getattr(e, "status_code", 500)
|
||||
exception_body = getattr(e, "body", None)
|
||||
error_headers = getattr(e, "headers", None)
|
||||
if error_headers is None and exception_response:
|
||||
error_headers = getattr(exception_response, "headers", None)
|
||||
message = getattr(e, "message", str(e))
|
||||
|
||||
raise OpenAIError(
|
||||
status_code=status_code, message=message, headers=error_headers
|
||||
status_code=status_code,
|
||||
message=message,
|
||||
headers=error_headers,
|
||||
body=exception_body,
|
||||
)
|
||||
|
||||
def streaming(
|
||||
@ -973,6 +981,7 @@ class OpenAIChatCompletion(BaseLLM):
|
||||
error_headers = getattr(e, "headers", None)
|
||||
status_code = getattr(e, "status_code", 500)
|
||||
error_response = getattr(e, "response", None)
|
||||
exception_body = getattr(e, "body", None)
|
||||
if error_headers is None and error_response:
|
||||
error_headers = getattr(error_response, "headers", None)
|
||||
if response is not None and hasattr(response, "text"):
|
||||
@ -980,6 +989,7 @@ class OpenAIChatCompletion(BaseLLM):
|
||||
status_code=status_code,
|
||||
message=f"{str(e)}\n\nOriginal Response: {response.text}", # type: ignore
|
||||
headers=error_headers,
|
||||
body=exception_body,
|
||||
)
|
||||
else:
|
||||
if type(e).__name__ == "ReadTimeout":
|
||||
@ -987,16 +997,21 @@ class OpenAIChatCompletion(BaseLLM):
|
||||
status_code=408,
|
||||
message=f"{type(e).__name__}",
|
||||
headers=error_headers,
|
||||
body=exception_body,
|
||||
)
|
||||
elif hasattr(e, "status_code"):
|
||||
raise OpenAIError(
|
||||
status_code=getattr(e, "status_code", 500),
|
||||
message=str(e),
|
||||
headers=error_headers,
|
||||
body=exception_body,
|
||||
)
|
||||
else:
|
||||
raise OpenAIError(
|
||||
status_code=500, message=f"{str(e)}", headers=error_headers
|
||||
status_code=500,
|
||||
message=f"{str(e)}",
|
||||
headers=error_headers,
|
||||
body=exception_body,
|
||||
)
|
||||
|
||||
def get_stream_options(
|
||||
|
||||
@ -1,4 +1,17 @@
|
||||
model_list:
|
||||
- model_name: llama3.2-vision
|
||||
- model_name: gpt-3.5-turbo
|
||||
litellm_params:
|
||||
model: ollama/llama3.2-vision
|
||||
model: gpt-3.5-turbo
|
||||
- model_name: gpt-4o
|
||||
litellm_params:
|
||||
model: azure/gpt-4o
|
||||
api_key: os.environ/AZURE_API_KEY
|
||||
api_base: os.environ/AZURE_API_BASE
|
||||
- model_name: fake-openai-endpoint-5
|
||||
litellm_params:
|
||||
model: openai/my-fake-model
|
||||
api_key: my-fake-key
|
||||
api_base: https://exampleopenaiendpoint-production.up.railway.app/
|
||||
timeout: 1
|
||||
litellm_settings:
|
||||
fallbacks: [{"gpt-3.5-turbo": ["gpt-4o"]}]
|
||||
|
||||
@ -1994,13 +1994,14 @@ class ProxyException(Exception):
|
||||
message: str,
|
||||
type: str,
|
||||
param: Optional[str],
|
||||
code: Optional[Union[int, str]] = None,
|
||||
code: Optional[Union[int, str]] = None, # maps to status code
|
||||
headers: Optional[Dict[str, str]] = None,
|
||||
openai_code: Optional[str] = None, # maps to 'code' in openai
|
||||
):
|
||||
self.message = str(message)
|
||||
self.type = type
|
||||
self.param = param
|
||||
|
||||
self.openai_code = openai_code or code
|
||||
# If we look on official python OpenAI lib, the code should be a string:
|
||||
# https://github.com/openai/openai-python/blob/195c05a64d39c87b2dfdf1eca2d339597f1fce03/src/openai/types/shared/error_object.py#L11
|
||||
# Related LiteLLM issue: https://github.com/BerriAI/litellm/discussions/4834
|
||||
|
||||
@ -3716,6 +3716,7 @@ async def chat_completion( # noqa: PLR0915
|
||||
message=getattr(e, "message", error_msg),
|
||||
type=getattr(e, "type", "None"),
|
||||
param=getattr(e, "param", "None"),
|
||||
openai_code=getattr(e, "code", None),
|
||||
code=getattr(e, "status_code", 500),
|
||||
headers=headers,
|
||||
)
|
||||
@ -3929,6 +3930,7 @@ async def completion( # noqa: PLR0915
|
||||
message=getattr(e, "message", error_msg),
|
||||
type=getattr(e, "type", "None"),
|
||||
param=getattr(e, "param", "None"),
|
||||
openai_code=getattr(e, "code", None),
|
||||
code=getattr(e, "status_code", 500),
|
||||
)
|
||||
|
||||
@ -4138,6 +4140,7 @@ async def embeddings( # noqa: PLR0915
|
||||
message=getattr(e, "message", error_msg),
|
||||
type=getattr(e, "type", "None"),
|
||||
param=getattr(e, "param", "None"),
|
||||
openai_code=getattr(e, "code", None),
|
||||
code=getattr(e, "status_code", 500),
|
||||
)
|
||||
|
||||
@ -4257,6 +4260,7 @@ async def image_generation(
|
||||
message=getattr(e, "message", error_msg),
|
||||
type=getattr(e, "type", "None"),
|
||||
param=getattr(e, "param", "None"),
|
||||
openai_code=getattr(e, "code", None),
|
||||
code=getattr(e, "status_code", 500),
|
||||
)
|
||||
|
||||
@ -4518,6 +4522,7 @@ async def audio_transcriptions(
|
||||
message=getattr(e, "message", error_msg),
|
||||
type=getattr(e, "type", "None"),
|
||||
param=getattr(e, "param", "None"),
|
||||
openai_code=getattr(e, "code", None),
|
||||
code=getattr(e, "status_code", 500),
|
||||
)
|
||||
|
||||
@ -4667,6 +4672,7 @@ async def get_assistants(
|
||||
message=getattr(e, "message", error_msg),
|
||||
type=getattr(e, "type", "None"),
|
||||
param=getattr(e, "param", "None"),
|
||||
openai_code=getattr(e, "code", None),
|
||||
code=getattr(e, "status_code", 500),
|
||||
)
|
||||
|
||||
@ -4765,7 +4771,7 @@ async def create_assistant(
|
||||
message=getattr(e, "message", error_msg),
|
||||
type=getattr(e, "type", "None"),
|
||||
param=getattr(e, "param", "None"),
|
||||
code=getattr(e, "status_code", 500),
|
||||
code=getattr(e, "code", getattr(e, "status_code", 500)),
|
||||
)
|
||||
|
||||
|
||||
@ -4862,7 +4868,7 @@ async def delete_assistant(
|
||||
message=getattr(e, "message", error_msg),
|
||||
type=getattr(e, "type", "None"),
|
||||
param=getattr(e, "param", "None"),
|
||||
code=getattr(e, "status_code", 500),
|
||||
code=getattr(e, "code", getattr(e, "status_code", 500)),
|
||||
)
|
||||
|
||||
|
||||
@ -4959,7 +4965,7 @@ async def create_threads(
|
||||
message=getattr(e, "message", error_msg),
|
||||
type=getattr(e, "type", "None"),
|
||||
param=getattr(e, "param", "None"),
|
||||
code=getattr(e, "status_code", 500),
|
||||
code=getattr(e, "code", getattr(e, "status_code", 500)),
|
||||
)
|
||||
|
||||
|
||||
@ -5055,7 +5061,7 @@ async def get_thread(
|
||||
message=getattr(e, "message", error_msg),
|
||||
type=getattr(e, "type", "None"),
|
||||
param=getattr(e, "param", "None"),
|
||||
code=getattr(e, "status_code", 500),
|
||||
code=getattr(e, "code", getattr(e, "status_code", 500)),
|
||||
)
|
||||
|
||||
|
||||
@ -5154,7 +5160,7 @@ async def add_messages(
|
||||
message=getattr(e, "message", error_msg),
|
||||
type=getattr(e, "type", "None"),
|
||||
param=getattr(e, "param", "None"),
|
||||
code=getattr(e, "status_code", 500),
|
||||
code=getattr(e, "code", getattr(e, "status_code", 500)),
|
||||
)
|
||||
|
||||
|
||||
@ -5249,7 +5255,7 @@ async def get_messages(
|
||||
message=getattr(e, "message", error_msg),
|
||||
type=getattr(e, "type", "None"),
|
||||
param=getattr(e, "param", "None"),
|
||||
code=getattr(e, "status_code", 500),
|
||||
code=getattr(e, "code", getattr(e, "status_code", 500)),
|
||||
)
|
||||
|
||||
|
||||
@ -5358,7 +5364,7 @@ async def run_thread(
|
||||
message=getattr(e, "message", error_msg),
|
||||
type=getattr(e, "type", "None"),
|
||||
param=getattr(e, "param", "None"),
|
||||
code=getattr(e, "status_code", 500),
|
||||
code=getattr(e, "code", getattr(e, "status_code", 500)),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@ -1205,3 +1205,35 @@ def test_context_window_exceeded_error_from_litellm_proxy():
|
||||
}
|
||||
with pytest.raises(litellm.ContextWindowExceededError):
|
||||
extract_and_raise_litellm_exception(**args)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("sync_mode", [True, False])
|
||||
@pytest.mark.parametrize("stream_mode", [True, False])
|
||||
@pytest.mark.parametrize("model", ["azure/gpt-4o"]) # "gpt-4o-mini",
|
||||
@pytest.mark.asyncio
|
||||
async def test_exception_bubbling_up(sync_mode, stream_mode, model):
|
||||
"""
|
||||
make sure code, param, and type are bubbled up
|
||||
"""
|
||||
import litellm
|
||||
|
||||
litellm.set_verbose = True
|
||||
with pytest.raises(Exception) as exc_info:
|
||||
if sync_mode:
|
||||
litellm.completion(
|
||||
model=model,
|
||||
messages=[{"role": "usera", "content": "hi"}],
|
||||
stream=stream_mode,
|
||||
sync_stream=sync_mode,
|
||||
)
|
||||
else:
|
||||
await litellm.acompletion(
|
||||
model=model,
|
||||
messages=[{"role": "usera", "content": "hi"}],
|
||||
stream=stream_mode,
|
||||
sync_stream=sync_mode,
|
||||
)
|
||||
|
||||
assert exc_info.value.code == "invalid_value"
|
||||
assert exc_info.value.param is not None
|
||||
assert exc_info.value.type == "invalid_request_error"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user