{"record":{"id":"31da22ee0ca9a592","repo":"BerriAI/litellm","slug":"no-keys-found-for-team-data-team-id","errorCode":null,"errorMessage":"No keys found for team {data.team_id}","messagePattern":"No keys found for team (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"warning","filePath":"litellm/proxy/management_endpoints/key_management_endpoints.py","lineNumber":3222,"sourceCode":"                token=\"__team_scope_auth_check__\",\n                team_id=data.team_id,\n                models=[],\n            )\n        )\n        await TeamMemberPermissionChecks.can_team_member_execute_key_management_endpoint(\n            user_api_key_dict=user_api_key_dict,\n            route=KeyManagementRoutes.KEY_UPDATE,\n            prisma_client=prisma_client,\n            existing_key_row=auth_anchor,\n            user_api_key_cache=user_api_key_cache,\n        )\n\n    # Block metadata.allowed_passthrough_routes for non-admins — the runtime\n    # route checker reads it from key/team metadata to grant passthrough.\n    _check_passthrough_routes_caller_permission(data=data.update_fields, user_api_key_dict=user_api_key_dict)\n\n    if not requested_tokens:\n        raise HTTPException(\n            status_code=404,\n            detail={\"error\": f\"No keys found for team {data.team_id}\"},\n        )\n\n    existing_by_token: Final = {row.token: row for row in existing_keys}\n    update_field_dict: Final = data.update_fields.model_dump(exclude_unset=True)\n\n    successful_updates: Final[list[SuccessfulKeyUpdate]] = []\n    failed_updates: Final[list[FailedKeyUpdate]] = []\n\n    for token in requested_tokens:\n        db_token = _hash_token_if_needed(token)\n        try:\n            if db_token not in existing_by_token:\n                raise HTTPException(\n                    status_code=404,\n                    detail={\"error\": f\"Key not found in team {data.team_id}\"},\n                )","sourceCodeStart":3204,"sourceCodeEnd":3240,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/management_endpoints/key_management_endpoints.py#L3204-L3240","documentation":"POST /team/key/bulk_update with all_keys_in_team=true queried the team's keys filtered to active ones (blocked=false/null AND (expires is null OR expires > now)) and got zero rows. Because the 'all keys' mode derives its target list from that query, an empty result means there is nothing to update, so the endpoint returns 404 instead of reporting a no-op success. Note the filter excludes blocked and expired keys by design (bulk refresh must not revive admin-disabled keys).","triggerScenarios":"Calling /team/key/bulk_update with all_keys_in_team=true for a team_id whose keys are all expired, all blocked, or that simply has no keys; passing a wrong or stale team_id.","commonSituations":"Running a scheduled bulk budget refresh after all team keys expired at month end; team keys were bulk-blocked during an incident and the automation still tries to update them; typo'd team_id that exists nowhere (other endpoints also 404).","solutions":["Verify the team actually has active keys: GET /team/info (with expand) or POST /v2/key/info filtered by the team.","If the keys are blocked/expired and you truly want to update them anyway, list their tokens explicitly in key_ids — the explicit path does not filter on blocked/expired.","Confirm the team_id value matches an existing team (GET /team/info?team_id=...)."],"exampleFix":"# before\nclient.post(\"/team/key/bulk_update\", json={\"team_id\": tid, \"all_keys_in_team\": True, \"update_fields\": fields})\n\n# after\nactive = [k for k in list_team_keys(tid) if k.get(\"blocked\") is not True and not key_expired(k)]\nif not active:\n    log.warning(\"team %s has no active keys; nothing to bulk update\", tid)\nelse:\n    client.post(\"/team/key/bulk_update\", json={\"team_id\": tid, \"key_ids\": [k[\"token\"] for k in active][:500], \"update_fields\": fields})","handlingStrategy":"try-catch","validationCode":"active = [k for k in list_team_keys(tid) if not k.get(\"blocked\") and not key_expired(k)]\nif not active:\n    log.warning(\"team %s has no active keys; skipping bulk update\", tid)\n    return","typeGuard":null,"tryCatchPattern":"try:\n    resp = client.post(\"/team/key/bulk_update\", json={\"team_id\": tid, \"all_keys_in_team\": True, ...})\n    resp.raise_for_status()\nexcept HTTPError as e:\n    if e.response.status_code == 404:\n        log.warning(\"no active keys in team %s; nothing to update\", tid)\n    else:\n        raise","preventionTips":["Check for active keys immediately before the bulk call instead of trusting a cached count.","Remember the 'all keys' mode intentionally skips blocked and expired keys — treat both as out of scope.","Alert when a regularly-updated team suddenly reports zero active keys; it usually signals expiry or a mass block."],"tags":["not-found","key-management","bulk-update","litellm-proxy"],"backgroundTag":"resource-not-found","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}