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
- 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
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
- 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
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
- LLM router not found. Please set it up by passing in a valid
- User does not have permission to view mcp server with id {se
- User {user_api_key_dict.user_id} does not have access to vec
- 404
- Model '{m}' not in team's allowed models. Team allowed model
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/a921d8b38b383312.
Report an issue: GitHub.