[Bug Fix] Virtual keys with llm_api type cause Internal Server Error when using /anthropic/* and other llm passthrough routes (#14046)

* fix route checks passthrough_routes_wildcard

* refactor check_route_access

* test_virtual_key_llm_api_route_includes_passthrough_prefix
This commit is contained in:
Ishaan Jaff 2025-08-28 15:14:09 -07:00
parent c58d4997ea
commit ab156ab4df
3 changed files with 63 additions and 2 deletions

View file

@ -326,6 +326,12 @@ class LiteLLMRoutes(enum.Enum):
"/mistral",
]
#########################################################
# e.g /vllm/*, anthropic/*, etc.
# allows using /anthropic/v1/messages, /vllm/v1/chat/completions, etc.
#########################################################
passthrough_routes_wildcard = [f"{route}/*" for route in mapped_pass_through_routes]
anthropic_routes = [
"/v1/messages",
]
@ -356,6 +362,7 @@ class LiteLLMRoutes(enum.Enum):
openai_routes
+ anthropic_routes
+ mapped_pass_through_routes
+ passthrough_routes_wildcard
+ apply_guardrail_routes
+ mcp_routes
)

View file

@ -300,6 +300,13 @@ class RouteChecks:
if re.match(pattern, route):
return True
return False
@staticmethod
def _is_wildcard_pattern(pattern: str) -> bool:
"""
Check if pattern is a wildcard pattern
"""
return pattern.endswith("*")
@staticmethod
def _route_matches_wildcard_pattern(route: str, pattern: str) -> bool:
@ -342,10 +349,34 @@ class RouteChecks:
Returns:
bool: True if route is allowed, False otherwise
"""
return route in allowed_routes or any( # Check exact match
#########################################################
# exact match route is in allowed_routes
#########################################################
if route in allowed_routes:
return True
#########################################################
# wildcard match route is in allowed_routes
# e.g calling /anthropic/v1/messages is allowed if allowed_routes has /anthropic/*
#########################################################
wildcard_allowed_routes = [route for route in allowed_routes if RouteChecks._is_wildcard_pattern(pattern=route)]
for allowed_route in wildcard_allowed_routes:
if RouteChecks._route_matches_wildcard_pattern(route=route, pattern=allowed_route):
return True
#########################################################
# pattern match route is in allowed_routes
# pattern: "/threads/{thread_id}"
# route: "/threads/thread_49EIN5QF32s4mH20M7GFKdlZ"
# returns: True
#########################################################
if any( # Check pattern match
RouteChecks._route_matches_pattern(route=route, pattern=allowed_route)
for allowed_route in allowed_routes
) # Check pattern match
):
return True
return False
@staticmethod
def _is_assistants_api_request(request: Request) -> bool:

View file

@ -130,6 +130,29 @@ def test_virtual_key_allowed_routes_with_litellm_routes_member_name_denied():
assert "Only allowed to call routes: ['info_routes']" in str(exc_info.value)
assert "Tried to call route: /chat/completions" in str(exc_info.value)
@pytest.mark.parametrize("route", [
"/anthropic/v1/messages",
"/anthropic/v1/count_tokens",
"/gemini/v1/models",
"/gemini/countTokens",
])
def test_virtual_key_llm_api_route_includes_passthrough_prefix(route):
"""
Virtual key with llm_api_routes should allow passthrough routes like /anthropic/v1/messages
Relevant issue: https://github.com/BerriAI/litellm/issues/14017
"""
valid_token = UserAPIKeyAuth(
user_id="test_user", allowed_routes=["llm_api_routes"]
)
result = RouteChecks.is_virtual_key_allowed_to_call_route(
route=route, valid_token=valid_token
)
assert result is True
def test_virtual_key_allowed_routes_with_multiple_litellm_routes_member_names():
"""Test that virtual key works with multiple LiteLLMRoutes member names in allowed_routes"""