diff --git a/litellm/proxy/auth/user_api_key_auth.py b/litellm/proxy/auth/user_api_key_auth.py index c992cfb53e..70ed7ad3c8 100644 --- a/litellm/proxy/auth/user_api_key_auth.py +++ b/litellm/proxy/auth/user_api_key_auth.py @@ -50,7 +50,7 @@ from litellm.proxy.common_utils.http_parsing_utils import ( _read_request_body, _safe_get_request_headers, populate_request_with_path_params) from litellm.proxy.common_utils.realtime_utils import _realtime_request_body -from litellm.proxy.utils import PrismaClient, ProxyLogging +from litellm.proxy.utils import PrismaClient, ProxyLogging, normalize_route_for_root_path from litellm.secret_managers.main import get_secret_bool from litellm.types.services import ServiceTypes @@ -386,9 +386,12 @@ async def check_api_key_for_custom_headers_or_pass_through_endpoints( api_key: str, ) -> Union[UserAPIKeyAuth, str]: is_mapped_pass_through_route: bool = False - for mapped_route in LiteLLMRoutes.mapped_pass_through_routes.value: # type: ignore - if route.startswith(mapped_route): - is_mapped_pass_through_route = True + normalized_route = normalize_route_for_root_path(route) + if normalized_route is not None: + for mapped_route in LiteLLMRoutes.mapped_pass_through_routes.value: # type: ignore + if normalized_route.startswith(mapped_route): + is_mapped_pass_through_route = True + break if is_mapped_pass_through_route: if request.headers.get("litellm_user_api_key") is not None: api_key = request.headers.get("litellm_user_api_key") or "" diff --git a/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py b/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py index 8cbc8b0399..9173758e2c 100644 --- a/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py +++ b/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py @@ -54,7 +54,7 @@ from litellm.proxy.common_utils.http_parsing_utils import ( _read_request_body, _safe_get_request_headers, ) -from litellm.proxy.utils import get_server_root_path +from litellm.proxy.utils import get_server_root_path, normalize_route_for_root_path from litellm.secret_managers.main import get_secret_str from litellm.types.llms.custom_http import httpxSpecialProvider from litellm.types.passthrough_endpoints.pass_through_endpoints import ( @@ -2061,9 +2061,11 @@ class InitPassThroughEndpointHelpers: bool: True if route is a registered pass-through endpoint, False otherwise """ ## CHECK IF MAPPED PASS THROUGH ENDPOINT - for mapped_route in LiteLLMRoutes.mapped_pass_through_routes.value: - if route.startswith(mapped_route): - return True + normalized_route = normalize_route_for_root_path(route) + if normalized_route is not None: + for mapped_route in LiteLLMRoutes.mapped_pass_through_routes.value: + if normalized_route.startswith(mapped_route): + return True # Fast path: check if any registered route key contains this path # Keys are in format: "{endpoint_id}:exact:{path}:{methods}" or "{endpoint_id}:subpath:{path}:{methods}" diff --git a/litellm/proxy/utils.py b/litellm/proxy/utils.py index ba6c6fa16e..f9fa422680 100644 --- a/litellm/proxy/utils.py +++ b/litellm/proxy/utils.py @@ -5196,6 +5196,16 @@ def get_server_root_path() -> str: return os.getenv("SERVER_ROOT_PATH", "") +def normalize_route_for_root_path(route: str) -> Optional[str]: + """Strip SERVER_ROOT_PATH prefix. Returns de-prefixed route, or None if route is not under root path.""" + root_path = get_server_root_path() + if root_path and root_path != "/": + if route.startswith(root_path + "/"): + return route[len(root_path):] + return None + return route + + def get_prisma_client_or_throw(message: str): from litellm.proxy.proxy_server import prisma_client diff --git a/tests/test_litellm/proxy/pass_through_endpoints/test_pass_through_endpoints.py b/tests/test_litellm/proxy/pass_through_endpoints/test_pass_through_endpoints.py index 5af24f9612..50459bf18a 100644 --- a/tests/test_litellm/proxy/pass_through_endpoints/test_pass_through_endpoints.py +++ b/tests/test_litellm/proxy/pass_through_endpoints/test_pass_through_endpoints.py @@ -2383,7 +2383,7 @@ def test_mapped_pass_through_routes_with_server_root_path(): ) with patch( - "litellm.proxy.pass_through_endpoints.pass_through_endpoints.get_server_root_path" + "litellm.proxy.utils.get_server_root_path" ) as mock_get_root: mock_get_root.return_value = "/litellm"