BerriAI/litellm · error · HTTPException

Key not found in team {data.team_id}

Error message

Key not found in team {data.team_id}

What it means

During POST /team/key/bulk_update in key_ids mode, LiteLLM first loads the team's existing key rows into a token->row map; a requested key whose (hashed) token is not in that map is recorded as a failed update with this 404 message. The key either belongs to a different team, was deleted, or was mistyped — and because the update runs per key inside a loop, this failure is collected per key rather than aborting the whole batch.

Source

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

    _check_passthrough_routes_caller_permission(data=data.update_fields, user_api_key_dict=user_api_key_dict)

    if not requested_tokens:
        raise HTTPException(
            status_code=404,
            detail={"error": f"No keys found for team {data.team_id}"},
        )

    existing_by_token: Final = {row.token: row for row in existing_keys}
    update_field_dict: Final = data.update_fields.model_dump(exclude_unset=True)

    successful_updates: Final[list[SuccessfulKeyUpdate]] = []
    failed_updates: Final[list[FailedKeyUpdate]] = []

    for token in requested_tokens:
        db_token = _hash_token_if_needed(token)
        try:
            if db_token not in existing_by_token:
                raise HTTPException(
                    status_code=404,
                    detail={"error": f"Key not found in team {data.team_id}"},
                )

            # team_id from validated scope, never user payload — drives _check_team_key_limits.
            update_key_request = UpdateKeyRequest.model_validate(
                {
                    "key": token,
                    "team_id": data.team_id,
                    **update_field_dict,
                }
            )
            updated_key_info = await _process_single_key_update(
                update_key_request=update_key_request,
                user_api_key_dict=user_api_key_dict,
                litellm_changed_by=litellm_changed_by,
                prisma_client=prisma_client,
                user_api_key_cache=user_api_key_cache,

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Inspect the failed_updates array in the BulkUpdateKeyResponse — only the listed keys failed; the rest were updated.
  2. Re-fetch the current team keys (GET /team/info or /v2/key/info) and rerun the bulk update with the intersection of your list and the live list.
  3. Make your listing and update steps short-lived so keys are less likely to disappear in between; treat per-key 404 as expected and prunable.

Example fix

# before
resp = client.post("/team/key/bulk_update", json={"team_id": tid, "key_ids": my_cached_ids, "update_fields": fields})

# after
live_ids = set(get_team_key_ids(tid))
usable = [k for k in my_cached_ids if k in live_ids]
resp = client.post("/team/key/bulk_update", json={"team_id": tid, "key_ids": usable, "update_fields": fields})
for f in resp.json().get("failed_updates", []):
    log.warning("key %s failed: %s", f["key"], f["error"])
Defensive patterns

Strategy: try-catch

Validate before calling

live_tokens = set(fetch_team_key_ids(tid))
requestable = [k for k in my_key_ids if k in live_tokens]
dropped = set(my_key_ids) - live_tokens
if dropped:
    log.warning("dropping %d keys no longer in team %s: %s", len(dropped), tid, dropped)

Try / catch

# Per-key failures are returned in the response body, not thrown — inspect them:
result = client.post("/team/key/bulk_update", json={...}).json()
for fail in result.get("failed_updates", []):
    if "Key not found in team" in str(fail.get("error", "")):
        prune_from_local_cache(fail["key"])
    else:
        escalate(fail)

Prevention

When it happens

Trigger: Including a key token that was rotated/deleted between your listing call and the bulk update; passing keys that belong to another team; passing unhashed tokens when the DB stores hashed tokens after enabling KEY_DB checkpoints (note _hash_token_if_needed normalizes this, so the usual cause is wrong team or deleted key).

Common situations: Race between an admin deleting keys and your bulk job running; stale key list cached from an earlier export; copying key IDs between environments (dev key sent to prod proxy).

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/5c2ef9b32fa3795f. Report an issue: GitHub.