Fix duplicate validation, None dereference, and JSONDecodeError

- Remove duplicate validation block from update_key_fn — team limits,
  project limits, team-change, and MCP server checks are already
  performed in full by _validate_update_key_data called just above
- Guard against None return from get_team_object in fetch_all_mcp_servers
  before accessing team_obj.members_with_roles (raises 404 on unknown team)
- Wrap json.loads in _resolve_team_allowed_mcp_servers with try/except
  JSONDecodeError so a malformed stored string falls back to {} instead
  of surfacing an unhandled exception

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
yuneng-jiang 2026-03-17 13:51:36 -07:00
parent 9c8659e28d
commit 8664612ab2
3 changed files with 14 additions and 77 deletions

View file

@ -2052,82 +2052,6 @@ async def update_key_fn(
user_api_key_cache=user_api_key_cache,
)
# Only check team limits if key has a team_id
team_obj: Optional[LiteLLM_TeamTableCachedObj] = None
if data.team_id is not None:
team_obj = await get_team_object(
team_id=data.team_id,
prisma_client=prisma_client,
user_api_key_cache=user_api_key_cache,
check_db_only=True,
)
if team_obj is not None:
await _check_team_key_limits(
team_table=team_obj,
data=data,
prisma_client=prisma_client,
)
# Validate key against project limits if project_id is being set
_project_id_to_check = getattr(data, "project_id", None) or getattr(
existing_key_row, "project_id", None
)
if _project_id_to_check is not None and (
data.models is not None or data.max_budget is not None
):
await _check_project_key_limits(
project_id=_project_id_to_check,
data=data,
prisma_client=prisma_client,
user_api_key_cache=user_api_key_cache,
)
# if team change - check if this is possible
if is_different_team(data=data, existing_key_row=existing_key_row):
if llm_router is None:
raise HTTPException(
status_code=400,
detail={
"error": "LLM router not found. Please set it up by passing in a valid config.yaml or adding models via the UI."
},
)
# team_obj should be set since is_different_team() returns True only when data.team_id is not None
if team_obj is None:
raise HTTPException(
status_code=500,
detail={
"error": "Team object not found for team change validation"
},
)
await validate_key_team_change(
key=existing_key_row,
team=team_obj,
change_initiated_by=user_api_key_dict,
llm_router=llm_router,
)
# Validate MCP servers in object_permission against the effective team
if data.object_permission is not None:
effective_team_obj = team_obj
# If team_id isn't being changed, resolve the existing key's team
if effective_team_obj is None and existing_key_row.team_id:
effective_team_obj = await get_team_object(
team_id=existing_key_row.team_id,
prisma_client=prisma_client,
user_api_key_cache=user_api_key_cache,
check_db_only=True,
)
object_permission_dict = (
data.object_permission.model_dump()
if hasattr(data.object_permission, "model_dump")
else data.object_permission
)
await validate_key_mcp_servers_against_team(
object_permission=object_permission_dict,
team_obj=effective_team_obj,
)
non_default_values = await prepare_key_update_data(
data=data, existing_key_row=existing_key_row
)

View file

@ -739,6 +739,11 @@ if MCP_AVAILABLE:
user_api_key_cache=user_api_key_cache,
check_db_only=True,
)
if team_obj is None:
raise HTTPException(
status_code=404,
detail=f"Team not found: {sanitized_team_id}",
)
user_in_team = any(
m.user_id is not None and m.user_id == user_api_key_dict.user_id
for m in team_obj.members_with_roles

View file

@ -215,7 +215,15 @@ async def _resolve_team_allowed_mcp_servers(
)
raw_tool_perms = team_object_permission.mcp_tool_permissions or {}
if isinstance(raw_tool_perms, str):
raw_tool_perms = json.loads(raw_tool_perms)
try:
raw_tool_perms = json.loads(raw_tool_perms)
except json.JSONDecodeError:
verbose_proxy_logger.warning(
"Failed to deserialize mcp_tool_permissions as JSON; treating as empty. "
"Value: %r",
raw_tool_perms,
)
raw_tool_perms = {}
tool_perm_servers: List[str] = list(raw_tool_perms.keys())
return set(direct_servers + access_group_servers + tool_perm_servers)