From c0d6c1085e253ba8fc213a01130e4c1faae5e1f3 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Mon, 23 Mar 2026 18:13:35 +0530 Subject: [PATCH] fix(routing): address state consistency and type safety issues - Check alias target pattern to detect stale team aliases - Fix PrismaClient type annotation to Optional - Eliminate in-place mutation in index update logic Made-with: Cursor --- litellm/proxy/litellm_pre_call_utils.py | 19 +++++++++----- .../model_management_endpoints.py | 2 +- litellm/router.py | 26 ++++++++++--------- 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/litellm/proxy/litellm_pre_call_utils.py b/litellm/proxy/litellm_pre_call_utils.py index 5de27bb7145..d8ed29b0475 100644 --- a/litellm/proxy/litellm_pre_call_utils.py +++ b/litellm/proxy/litellm_pre_call_utils.py @@ -1310,13 +1310,20 @@ def _update_model_if_team_alias_exists( # Skip alias rewrite if this model resolves to team-specific deployments # (team models use team_public_model_name, not model_aliases) - # Use O(1) index lookup instead of map_team_model to avoid O(n) scan - if llm_router and user_api_key_dict.team_id: - key = (user_api_key_dict.team_id, _model) - if key in llm_router.team_model_to_deployment_indices: - return + aliased_target = user_api_key_dict.team_model_aliases[_model] - data["model"] = user_api_key_dict.team_model_aliases[_model] + # Check if the alias points to a stale team-scoped UUID name + # (format: "model_name_{team_id}_{uuid}") + if aliased_target.startswith(f"model_name_{user_api_key_dict.team_id}_"): + # This is a stale alias from pre-PR deployments. + # Check if current team deployments exist for the public name. + if llm_router: + key = (user_api_key_dict.team_id, _model) + if key in llm_router.team_model_to_deployment_indices: + # Team deployments exist; skip stale alias + return + + data["model"] = aliased_target return diff --git a/litellm/proxy/management_endpoints/model_management_endpoints.py b/litellm/proxy/management_endpoints/model_management_endpoints.py index 7682b65657a..7d0181a3687 100644 --- a/litellm/proxy/management_endpoints/model_management_endpoints.py +++ b/litellm/proxy/management_endpoints/model_management_endpoints.py @@ -466,7 +466,7 @@ async def _update_existing_team_model_assignment( db_model: Deployment, patch_data: updateDeployment, user_api_key_dict: UserAPIKeyAuth, - prisma_client: PrismaClient, + prisma_client: Optional[PrismaClient], ) -> None: """Update an existing team model if the public name changed.""" old_public_name = ( diff --git a/litellm/router.py b/litellm/router.py index 91381b3763f..fdc23fb5dd4 100644 --- a/litellm/router.py +++ b/litellm/router.py @@ -7057,16 +7057,17 @@ class Router: # Update model_name_to_deployment_indices for model_name, indices in list(self.model_name_to_deployment_indices.items()): - # Remove the deleted index - if removal_idx in indices: - indices.remove(removal_idx) - - # Decrement all indices greater than removal_idx + # Build new list without mutating the original updated_indices = [] for idx in indices: - if idx > removal_idx: + if idx == removal_idx: + # Skip the removed index + continue + elif idx > removal_idx: + # Decrement indices after removal updated_indices.append(idx - 1) else: + # Keep indices before removal unchanged updated_indices.append(idx) # Update or remove the entry @@ -7077,16 +7078,17 @@ class Router: # Update team_model_to_deployment_indices for key, indices in list(self.team_model_to_deployment_indices.items()): - # Remove the deleted index - if removal_idx in indices: - indices.remove(removal_idx) - - # Decrement all indices greater than removal_idx + # Build new list without mutating the original updated_indices = [] for idx in indices: - if idx > removal_idx: + if idx == removal_idx: + # Skip the removed index + continue + elif idx > removal_idx: + # Decrement indices after removal updated_indices.append(idx - 1) else: + # Keep indices before removal unchanged updated_indices.append(idx) # Update or remove the entry