BerriAI/litellm · error · HTTPException

Team not found for team_id={data.team_id}. Non-admin users c

Error message

Team not found for team_id={data.team_id}. Non-admin users cannot create keys for non-existent teams.

What it means

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.

Source

Thrown at litellm/proxy/management_endpoints/key_management_endpoints.py:1750

                "key/generate: auto-assigning user_id=%s for non-admin caller",
                user_api_key_dict.user_id,
            )

        team_table: LiteLLM_TeamTableCachedObj | None = None
        if data.team_id is not None:
            try:
                team_table = await get_team_object(
                    team_id=data.team_id,
                    prisma_client=prisma_client,
                    user_api_key_cache=user_api_key_cache,
                    parent_otel_span=user_api_key_dict.parent_otel_span,
                    check_db_only=True,
                )
            except Exception as e:
                verbose_proxy_logger.debug("Error getting team object in `/key/generate`: %s", e)
                # For non-admin callers, team must exist (LIT-1884)
                if not _is_proxy_admin:
                    raise HTTPException(
                        status_code=400,
                        detail=f"Team not found for team_id={data.team_id}. Non-admin users cannot create keys for non-existent teams.",
                    )

        key_generation_check(
            team_table=team_table,
            user_api_key_dict=user_api_key_dict,
            data=data,
            route=KeyManagementRoutes.KEY_GENERATE,
        )

        if team_table is not None:
            await _check_team_key_limits(
                team_table=team_table,
                data=data,
                prisma_client=prisma_client,
            )

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Verify the team exists first: GET /team/list and confirm the exact team_id
  2. Create the team before generating keys: POST /team/new, then use the returned team_id
  3. Fix copy/paste drift in team_id (whitespace, wrong UUID, old environment's ID)
  4. If the caller genuinely must bypass existence checks, use a proxy admin (master) key -- but prefer fixing the team_id

Example fix

# before
await client.post("/key/generate", json={"team_id": "team-prod-123", ...})  # typo / stale id

# after
teams = (await client.get("/team/list")).json()
valid = {t["team_id"] for t in teams["teams"]}
assert "team-prod-123" in valid, "team does not exist; create it via POST /team/new first"
await client.post("/key/generate", json={"team_id": "team-prod-123", ...})
Defensive patterns

Strategy: validation

Validate before calling

teams = (await client.get("/team/list")).json()
valid_ids = {t["team_id"] for t in teams["teams"]}
if payload["team_id"] not in valid_ids:
    created = (await client.post("/team/new", json={"team_id": payload["team_id"]})).json()
    assert created["team_id"] == payload["team_id"]

Try / catch

try:
    r = await client.post("/key/generate", json=payload)
except httpx.HTTPStatusError as e:
    if e.response.status_code == 400 and "Team not found" in e.response.text:
        await ensure_team_exists(payload["team_id"]); r = await client.post("/key/generate", json=payload)
    else:
        raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/a921d8b38b383312. Report an issue: GitHub.