{"record":{"id":"a921d8b38b383312","repo":"BerriAI/litellm","slug":"team-not-found-for-team-id-data-team-id-non-adm","errorCode":null,"errorMessage":"Team not found for team_id={data.team_id}. Non-admin users cannot create keys for non-existent teams.","messagePattern":"Team not found for team_id=(.+?)\\. Non-admin users cannot create keys for non-existent teams\\.","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"litellm/proxy/management_endpoints/key_management_endpoints.py","lineNumber":1750,"sourceCode":"                \"key/generate: auto-assigning user_id=%s for non-admin caller\",\n                user_api_key_dict.user_id,\n            )\n\n        team_table: LiteLLM_TeamTableCachedObj | None = None\n        if data.team_id is not None:\n            try:\n                team_table = await get_team_object(\n                    team_id=data.team_id,\n                    prisma_client=prisma_client,\n                    user_api_key_cache=user_api_key_cache,\n                    parent_otel_span=user_api_key_dict.parent_otel_span,\n                    check_db_only=True,\n                )\n            except Exception as e:\n                verbose_proxy_logger.debug(\"Error getting team object in `/key/generate`: %s\", e)\n                # For non-admin callers, team must exist (LIT-1884)\n                if not _is_proxy_admin:\n                    raise HTTPException(\n                        status_code=400,\n                        detail=f\"Team not found for team_id={data.team_id}. Non-admin users cannot create keys for non-existent teams.\",\n                    )\n\n        key_generation_check(\n            team_table=team_table,\n            user_api_key_dict=user_api_key_dict,\n            data=data,\n            route=KeyManagementRoutes.KEY_GENERATE,\n        )\n\n        if team_table is not None:\n            await _check_team_key_limits(\n                team_table=team_table,\n                data=data,\n                prisma_client=prisma_client,\n            )\n","sourceCodeStart":1732,"sourceCodeEnd":1768,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/management_endpoints/key_management_endpoints.py#L1732-L1768","documentation":"In POST /key/generate, when a team_id is supplied LiteLLM tries to fetch the team; if the lookup raises and the caller is NOT a proxy admin, the request fails with HTTP 400 stating non-admin users cannot create keys for non-existent teams (internal ticket LIT-1884). Proxy admins are deliberately exempted because key generation may implicitly reference teams created out-of-band. Non-admin callers must reference an existing team.","triggerScenarios":"A team-member or internal-user key calls POST /key/generate with a typo'd or deleted team_id; the team exists in another environment (staging vs prod DB); the caller authenticated with a key that is not the master/admin key; team was soft-deleted so get_team_object raises.","commonSituations":"Scripts promoted between environments carrying hardcoded team_ids; a CI job generating team keys after the team was re-created with a new UUID; org admin assuming org-admin rights equal proxy-admin rights (they do not for this check); race where the team creation call failed earlier and the error was ignored.","solutions":["Verify the team exists first: GET /team/list and confirm the exact team_id","Create the team before generating keys: POST /team/new, then use the returned team_id","Fix copy/paste drift in team_id (whitespace, wrong UUID, old environment's ID)","If the caller genuinely must bypass existence checks, use a proxy admin (master) key -- but prefer fixing the team_id"],"exampleFix":"# before\nawait client.post(\"/key/generate\", json={\"team_id\": \"team-prod-123\", ...})  # typo / stale id\n\n# after\nteams = (await client.get(\"/team/list\")).json()\nvalid = {t[\"team_id\"] for t in teams[\"teams\"]}\nassert \"team-prod-123\" in valid, \"team does not exist; create it via POST /team/new first\"\nawait client.post(\"/key/generate\", json={\"team_id\": \"team-prod-123\", ...})","handlingStrategy":"validation","validationCode":"teams = (await client.get(\"/team/list\")).json()\nvalid_ids = {t[\"team_id\"] for t in teams[\"teams\"]}\nif payload[\"team_id\"] not in valid_ids:\n    created = (await client.post(\"/team/new\", json={\"team_id\": payload[\"team_id\"]})).json()\n    assert created[\"team_id\"] == payload[\"team_id\"]","typeGuard":null,"tryCatchPattern":"try:\n    r = await client.post(\"/key/generate\", json=payload)\nexcept httpx.HTTPStatusError as e:\n    if e.response.status_code == 400 and \"Team not found\" in e.response.text:\n        await ensure_team_exists(payload[\"team_id\"]); r = await client.post(\"/key/generate\", json=payload)\n    else:\n        raise","preventionTips":["Provision teams before keys: make /team/new a prerequisite step in every key-creation script","Never hardcode team_ids across environments; source them per-environment or discover via /team/list","Non-admin flows should validate the team_id exists first, since admins are the only ones allowed to bypass"],"tags":["litellm","proxy","teams","key-generation","authorization"],"backgroundTag":"resource-not-found","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}