BerriAI/litellm · error · HTTPException

Key={key.token} has a rpm_limit={key.rpm_limit} which is gre

Error message

Key={key.token} has a rpm_limit={key.rpm_limit} which is greater than the team's rpm_limit={team.rpm_limit}.

What it means

Same family as the tpm check: a key's rpm_limit may not exceed its team's rpm_limit. The guard lives with the other team-key limit checks (note the nesting — it only runs inside `if key.tpm_limit is not None`, i.e. when the key defines a tpm_limit) and returns 403 naming the key, its rpm_limit, and the team's rpm_limit.

Source

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

            # Skip special sentinel values — "all-team-models" means
            # "use whatever the team allows", so it's always valid.
            if model == SpecialModelNames.all_team_models.value:
                continue
            await can_team_access_model(
                model=model,
                team_object=team,
                llm_router=llm_router,
            )

    # Check if the key's tpm/rpm limit is less than the team's tpm/rpm limit
    if key.tpm_limit is not None:
        if team.tpm_limit and key.tpm_limit > team.tpm_limit:
            raise HTTPException(
                status_code=403,
                detail=f"Key={key.token} has a tpm_limit={key.tpm_limit} which is greater than the team's tpm_limit={team.tpm_limit}.",
            )
        if team.rpm_limit and key.rpm_limit and key.rpm_limit > team.rpm_limit:
            raise HTTPException(
                status_code=403,
                detail=f"Key={key.token} has a rpm_limit={key.rpm_limit} which is greater than the team's rpm_limit={team.rpm_limit}.",
            )

    # Check if the key's user_id is a member of the team
    member_object: Final = _get_user_in_team(team_table=cast(LiteLLM_TeamTableCachedObj, team), user_id=key.user_id)
    if key.user_id is not None:
        if not member_object:
            raise HTTPException(
                status_code=403,
                detail=f"User={key.user_id} is not a member of the team={team.team_id}. Check team members via `/team/info`.",
            )

    # Check if the person initiating the change is a Proxy Admin or Team Admin
    if (
        change_initiated_by.user_role == LitellmUserRoles.PROXY_ADMIN.value
        or _is_user_team_admin(
            user_api_key_dict=change_initiated_by,

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Raise the team's rpm_limit (POST /team/update) to >= the key's rpm_limit, then retry the key creation/update.
  2. Or lower the key's rpm_limit to <= the team's rpm_limit.
  3. Or omit rpm_limit on the key to inherit the team's allowance.

Example fix

# before
client.post("/key/generate", json={"team_id": tid, "rpm_limit": 1000})

# after
client.post("/team/update", json={"team_id": tid, "rpm_limit": 1000})
client.post("/key/generate", json={"team_id": tid, "rpm_limit": 1000})
Defensive patterns

Strategy: validation

Validate before calling

def assert_key_rpm_within_team(client, team_id: str, rpm_limit: int | None) -> None:
    if rpm_limit is None:
        return
    team = client.get("/team/info", params={"team_id": team_id}).json()
    team_rpm = team.get("rpm_limit")
    if team_rpm is not None and rpm_limit > team_rpm:
        raise ValueError(f"key rpm_limit {rpm_limit} > team rpm_limit {team_rpm}; raise team limit first")

Type guard

def key_rpm_fits_team(key_rpm: int | None, team_rpm: int | None) -> bool:
    return key_rpm is None or team_rpm is None or key_rpm <= team_rpm

Prevention

When it happens

Trigger: POST /key/generate or /key/update with team_id set, a tpm_limit defined on the key, and key rpm_limit > team rpm_limit (e.g. team rpm_limit=100, key rpm_limit=1000).

Common situations: Burst-tolerance tuning: giving a service key a high rpm_limit while the team still has the default low cap; syncing key settings from a spreadsheet where team and key limits drifted; also note the asymmetric nesting means a key with only rpm_limit set (tpm_limit null) skips this check entirely — a validation gap to be aware of.

Related errors


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