mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-18 04:44:37 +00:00
fix(vertex): match standalone 403 status tokens instead of any substring (#47134)
* fix(vertex): match standalone 403 status tokens Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(vertex): keep text 403 fallback for wrapped 500 errors Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(vertex): keep BadRequestError for explicit 403 text matches Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(vertex): let structured body codes override the 403 text fallback Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
4b635f18e4
commit
84d91bbe87
3 changed files with 138 additions and 3 deletions
|
|
@ -1196,6 +1196,9 @@ def _map_sagemaker_exception(
|
|||
)
|
||||
|
||||
|
||||
_VERTEX_403_STATUS_CODE_PATTERN: Final = re.compile(r"(?<![0-9A-Za-z])403(?![0-9A-Za-z])")
|
||||
|
||||
|
||||
def _map_vertex_exception(
|
||||
*,
|
||||
model: str,
|
||||
|
|
@ -1206,6 +1209,8 @@ def _map_vertex_exception(
|
|||
exception_provider: str,
|
||||
extra_information: str,
|
||||
) -> None:
|
||||
status_code: Final[object] = getattr(original_exception, "status_code", None)
|
||||
body_code: Final[int | None] = _get_body_error_code(error_str)
|
||||
if "Vertex AI API has not been used in project" in error_str or "Unable to find your project" in error_str:
|
||||
raise BadRequestError(
|
||||
message=f"litellm.BadRequestError: {custom_llm_provider}Exception - {error_str}",
|
||||
|
|
@ -1252,7 +1257,11 @@ def _map_vertex_exception(
|
|||
llm_provider=custom_llm_provider,
|
||||
litellm_debug_info=extra_information,
|
||||
)
|
||||
elif "403" in error_str:
|
||||
elif (
|
||||
(not isinstance(status_code, int) or status_code in (403, 500))
|
||||
and body_code in (None, 403)
|
||||
and _VERTEX_403_STATUS_CODE_PATTERN.search(error_str)
|
||||
):
|
||||
raise BadRequestError(
|
||||
message=f"{custom_llm_provider.capitalize()}Exception BadRequestError - {error_str}",
|
||||
model=model,
|
||||
|
|
@ -1306,7 +1315,7 @@ def _map_vertex_exception(
|
|||
elif (
|
||||
isinstance(getattr(original_exception, "status_code", None), int)
|
||||
and 500 <= original_exception.status_code < 600
|
||||
and _get_body_error_code(error_str) == 429
|
||||
and body_code == 429
|
||||
):
|
||||
# upstream gateway wraps a 429 inside a 5xx envelope
|
||||
# e.g. HTTP 500/503 with {"error":{"code":429,...}}.
|
||||
|
|
|
|||
|
|
@ -388,7 +388,7 @@ def test_adapter_route_upstream_error_reaches_the_caller_with_its_status(
|
|||
gateway: Gateway, status: int, stream: bool
|
||||
) -> None:
|
||||
route: Final = _ROUTES["model_garden_publisher"]
|
||||
message: Final = f"scripted vertex rejection {uuid.uuid4().hex}"
|
||||
message: Final = f"scripted vertex rejection {uuid.uuid4().hex}f4039"
|
||||
with wire_server(_vertex_peer(status=status, error=message)) as wire, gateway.scenario() as scenario:
|
||||
model: Final = _deployment(gateway, scenario, wire, route, num_retries=0)
|
||||
key: Final = scenario.key(models=[model])
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ from litellm.litellm_core_utils.exception_mapping_utils import (
|
|||
exception_type,
|
||||
extract_and_raise_litellm_exception,
|
||||
)
|
||||
from litellm.llms.base_llm.chat.transformation import BaseLLMException
|
||||
from litellm.llms.bedrock.common_utils import BedrockError
|
||||
from litellm.llms.custom_httpx.http_handler import AsyncHTTPHandler, HTTPHandler
|
||||
from litellm.llms.openai.common_utils import OpenAIError
|
||||
|
|
@ -578,6 +579,131 @@ def test_vertex_ai_rate_limit_error_mapping(error_message, should_raise_rate_lim
|
|||
)
|
||||
|
||||
|
||||
def test_vertex_status_code_429_ignores_403_token_in_message() -> None:
|
||||
original_exception: Final = BaseLLMException(status_code=429, message="scripted vertex rejection f4039")
|
||||
|
||||
with pytest.raises(litellm.RateLimitError) as excinfo:
|
||||
exception_type(
|
||||
model="gemini/gemini-2.5-flash",
|
||||
original_exception=original_exception,
|
||||
custom_llm_provider="vertex_ai",
|
||||
)
|
||||
|
||||
assert excinfo.value.status_code == 429
|
||||
|
||||
|
||||
def test_vertex_status_code_403_maps_to_403() -> None:
|
||||
original_exception: Final = BaseLLMException(status_code=403, message="permission denied")
|
||||
|
||||
with pytest.raises(litellm.PermissionDeniedError) as excinfo:
|
||||
exception_type(
|
||||
model="gemini/gemini-2.5-flash",
|
||||
original_exception=original_exception,
|
||||
custom_llm_provider="vertex_ai",
|
||||
)
|
||||
|
||||
assert excinfo.value.status_code == 403
|
||||
|
||||
|
||||
def test_vertex_status_code_403_with_text_token_maps_to_bad_request() -> None:
|
||||
original_exception: Final = BaseLLMException(
|
||||
status_code=403,
|
||||
message='{"error":{"code":403,"message":"Permission denied"}}',
|
||||
)
|
||||
|
||||
with pytest.raises(litellm.BadRequestError) as excinfo:
|
||||
exception_type(
|
||||
model="gemini/gemini-2.5-flash",
|
||||
original_exception=original_exception,
|
||||
custom_llm_provider="vertex_ai",
|
||||
)
|
||||
|
||||
assert excinfo.value.status_code == 403
|
||||
|
||||
|
||||
def test_vertex_text_403_without_status_code_still_maps_to_bad_request() -> None:
|
||||
with pytest.raises(litellm.BadRequestError) as excinfo:
|
||||
exception_type(
|
||||
model="gemini/gemini-2.5-flash",
|
||||
original_exception=Exception("403 Forbidden: permission denied"),
|
||||
custom_llm_provider="vertex_ai",
|
||||
)
|
||||
|
||||
assert excinfo.value.status_code == 403
|
||||
|
||||
|
||||
def test_vertex_status_substring_without_status_code_does_not_map_to_403() -> None:
|
||||
with pytest.raises(litellm.APIConnectionError) as excinfo:
|
||||
exception_type(
|
||||
model="gemini/gemini-2.5-flash",
|
||||
original_exception=Exception("scripted vertex rejection f4039a"),
|
||||
custom_llm_provider="vertex_ai",
|
||||
)
|
||||
|
||||
assert excinfo.value.status_code != 403
|
||||
|
||||
|
||||
def test_vertex_wrapped_500_with_403_body_maps_to_bad_request() -> None:
|
||||
original_exception: Final = BaseLLMException(
|
||||
status_code=500,
|
||||
message='Error code: 403 - {"error": {"code": 403, "message": "Permission denied"}}',
|
||||
)
|
||||
|
||||
with pytest.raises(litellm.BadRequestError) as excinfo:
|
||||
exception_type(
|
||||
model="gemini/gemini-2.5-flash",
|
||||
original_exception=original_exception,
|
||||
custom_llm_provider="vertex_ai",
|
||||
)
|
||||
|
||||
assert excinfo.value.status_code == 403
|
||||
|
||||
|
||||
def test_vertex_wrapped_500_with_embedded_403_text_does_not_map_to_403() -> None:
|
||||
original_exception: Final = BaseLLMException(status_code=500, message="scripted vertex rejection f4039")
|
||||
|
||||
with pytest.raises(litellm.InternalServerError) as excinfo:
|
||||
exception_type(
|
||||
model="gemini/gemini-2.5-flash",
|
||||
original_exception=original_exception,
|
||||
custom_llm_provider="vertex_ai",
|
||||
)
|
||||
|
||||
assert excinfo.value.status_code == 500
|
||||
|
||||
|
||||
def test_vertex_wrapped_500_with_body_code_429_and_403_token_maps_to_rate_limit() -> None:
|
||||
original_exception: Final = BaseLLMException(
|
||||
status_code=500,
|
||||
message='{"error":{"code":429,"message":"upstream unavailable (request id: 403-xyz)"}}',
|
||||
)
|
||||
|
||||
with pytest.raises(litellm.RateLimitError) as excinfo:
|
||||
exception_type(
|
||||
model="gemini/gemini-2.5-flash",
|
||||
original_exception=original_exception,
|
||||
custom_llm_provider="vertex_ai",
|
||||
)
|
||||
|
||||
assert excinfo.value.status_code == 429
|
||||
|
||||
|
||||
def test_vertex_wrapped_500_with_body_code_403_maps_to_bad_request() -> None:
|
||||
original_exception: Final = BaseLLMException(
|
||||
status_code=500,
|
||||
message='{"error":{"code":403,"message":"Permission denied"}}',
|
||||
)
|
||||
|
||||
with pytest.raises(litellm.BadRequestError) as excinfo:
|
||||
exception_type(
|
||||
model="gemini/gemini-2.5-flash",
|
||||
original_exception=original_exception,
|
||||
custom_llm_provider="vertex_ai",
|
||||
)
|
||||
|
||||
assert excinfo.value.status_code == 403
|
||||
|
||||
|
||||
class TestGetBodyErrorCode:
|
||||
"""Unit tests for _get_body_error_code helper."""
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue