BerriAI/litellm · error · HTTPException
Only proxy admins can enable throttle_on_budget_exceeded on
Error message
Only proxy admins can enable throttle_on_budget_exceeded on a key.
What it means
LiteLLM Proxy rejects key creation/update when the request body sets throttle_on_budget_exceeded=true but the authenticated caller is not a proxy admin (user_role != PROXY_ADMIN). This flag throttles (instead of blocks) a key once its budget is exceeded, an admin-only control. The check runs in _common_key_generation_helper, so it applies to both /key/generate and /key/update.
Source
Thrown at litellm/proxy/management_endpoints/key_management_endpoints.py:867
) -> GenerateKeyResponse:
from litellm.proxy.proxy_server import (
litellm_proxy_admin_name,
llm_router,
premium_user,
prisma_client,
)
common_key_access_checks(
user_api_key_dict=user_api_key_dict,
data=data,
llm_router=llm_router,
premium_user=premium_user,
)
validate_budget_duration(data.budget_duration)
if data.throttle_on_budget_exceeded is True and user_api_key_dict.user_role != LitellmUserRoles.PROXY_ADMIN.value:
raise HTTPException(
status_code=403,
detail={"error": "Only proxy admins can enable throttle_on_budget_exceeded on a key."},
)
enforce_output_token_estimates_are_admin_only(
data=data,
existing_metadata=None,
user_api_key_dict=user_api_key_dict,
entity="key",
)
if data.metadata is not None and data.metadata.get("service_account_id") is not None and data.team_id is None:
await validate_team_id_used_in_service_account_request(
team_id=data.team_id,
prisma_client=prisma_client,
)
# Capture caller-supplied max_budget and team_id before any defaults orView on GitHub (pinned to 77b7c6c40c)
Solutions
- Remove throttle_on_budget_exceeded from the request body if you do not need it
- Re-send the same request with a proxy admin virtual key (a key issued to the admin user, role proxy_admin)
- Have a proxy admin create/update the key on behalf of the non-admin caller
Example fix
// before (caller is a team admin key)
curl -X POST http://localhost:4000/key/generate \
-H "Authorization: Bearer sk-team-admin-key" \
-d '{"max_budget": 5, "throttle_on_budget_exceeded": true}'
// after (use the proxy admin key for this flag)
curl -X POST http://localhost:4000/key/generate \
-H "Authorization: Bearer sk-proxy-admin-key" \
-d '{"max_budget": 5, "throttle_on_budget_exceeded": true}' Defensive patterns
Strategy: validation
Validate before calling
// Only include the admin-only flag when authed as an admin
payload = {"max_budget": 5}
if caller_is_proxy_admin: # track this where you store credentials
payload["throttle_on_budget_exceeded"] = True
requests.post(f"{PROXY}/key/generate", headers=AUTH, json=payload) Try / catch
try:
resp = requests.post(f"{PROXY}/key/generate", headers=AUTH, json=payload)
resp.raise_for_status()
except requests.HTTPError as e:
if e.response.status_code == 403 and "throttle_on_budget_exceeded" in e.response.text:
# retry without the flag, or escalate to an admin key
payload.pop("throttle_on_budget_exceeded", None)
resp = requests.post(f"{PROXY}/key/generate", headers=AUTH, json=payload)
else:
raise Prevention
- Keep per-role request templates so non-admin callers never carry admin-only fields
- Audit copied curl/SDK examples for flags like throttle_on_budget_exceeded before reuse
- Store which of your keys are proxy-admin keys and gate admin-only operations on that flag in your client library
When it happens
Trigger: A POST /key/generate or POST /key/update request whose JSON body contains "throttle_on_budget_exceeded": true, sent with a virtual key whose role is internal_user, team_member, team_admin, or org_admin rather than proxy_admin.
Common situations: Automation scripts copy an admin-only flag from a template; a team admin tries to soften budget enforcement for their team's keys; the UI or a copied curl example includes the flag and the caller uses a non-admin key.
Related errors
- max_budget ({_requested_max_budget}) cannot exceed the calle
- Unable to record skill ownership: caller has no identity sco
- Skill not found: {skill_id}
- Invalid budget_reset_time {raw!r}; must be a quoted 24-hour
- Invalid budget_reset_time {raw!r}; expected a 24-hour 'HH:MM
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/680b66207e3d7cbb.
Report an issue: GitHub.