BerriAI/litellm · error · ProxyException
either key or key_alias must be provided
Error message
either key or key_alias must be provided
What it means
_get_and_validate_existing_key requires exactly one identifier for the target key: 'token' (the key itself) or 'key_alias'. If the caller supplies neither (empty request body, or only update fields like max_budget), it raises a ProxyException with HTTP 400 'either key or key_alias must be provided'. The request never reaches the database.
Source
Thrown at litellm/proxy/management_endpoints/key_management_endpoints.py:2182
if token is not None:
hashed_token: Final = _hash_token_if_needed(token=token)
existing_key_row: Final[LiteLLM_VerificationToken | None] = await _prisma_table(
VerificationTokenRepository(prisma_client)
).find_unique(where={"token": hashed_token})
if existing_key_row is None:
raise ProxyException(
message="Key not found.",
type=ProxyErrorTypes.not_found_error,
param="key",
code=status.HTTP_404_NOT_FOUND,
)
return existing_key_row
if key_alias is None:
raise ProxyException(
message="either key or key_alias must be provided",
type=ProxyErrorTypes.bad_request_error,
param="key",
code=status.HTTP_400_BAD_REQUEST,
)
rows: list[LiteLLM_VerificationToken] = await _prisma_table(VerificationTokenRepository(prisma_client)).find_many(
where={"key_alias": key_alias}, take=2
)
if len(rows) == 0:
raise ProxyException(
message=f"Key not found. No key with key_alias='{key_alias}'.",
type=ProxyErrorTypes.not_found_error,
param="key_alias",
code=status.HTTP_404_NOT_FOUND,
)
View on GitHub (pinned to 77b7c6c40c)
Solutions
- Include "key": "<the virtual key string>" in the request body
- Or include "key_alias": "<unique alias>" when you don't have the raw token
- Check your payload serializer isn't dropping None/empty fields you meant to set
- Log the outgoing JSON body before sending to catch field-name mistakes
Example fix
# before
await client.post("/key/update", json={"max_budget": 100})
# after
await client.post("/key/update", json={"key": "sk-abc123", "max_budget": 100}) Defensive patterns
Strategy: validation
Validate before calling
if not payload.get("key") and not payload.get("key_alias"):
raise ValueError("update payload must include 'key' or 'key_alias'")
await client.post("/key/update", json=payload) Type guard
def has_key_identifier(p: dict) -> bool:
return bool(p.get("key") or p.get("key_alias")) Try / catch
try:
r = await client.post("/key/update", json=payload)
except httpx.HTTPStatusError as e:
if e.response.status_code == 400 and "either key or key_alias" in e.response.text:
payload["key"] = resolve_key() # attach the identifier and resend
r = await client.post("/key/update", json=payload)
else:
raise Prevention
- Make your request builder require key or key_alias as a mandatory argument
- Watch serializers that drop None fields (e.g. exclude_none=True) and silently remove identifiers
- Unit-test payload construction so identifier-less updates never reach the wire
When it happens
Trigger: POST /key/update with only {"max_budget": 100}; a client that serializes None fields as omitted keys so both key and key_alias vanish from the JSON; passing the identifier under a wrong field name (e.g. "token" or "key_id" instead of "key"); UI form where the key selector defaulted to blank.
Common situations: Refactor renaming the request model field and forgetting the caller; SDK wrapper that builds the payload conditionally and skips identifiers when a variable is None; assuming the proxy can infer the key from auth headers used on the call.
Understand the failure class
Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.
Related errors
- max_budget must be a non-negative finite number. Received: {
- soft_budget must be a non-negative finite number. Received:
- {reserved_field} is immutable once set and cannot be changed
- LLM router not found. Please set it up by passing in a valid
- max_budget cannot be negative. Received: {data.max_budget}
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/f37c472369d29832.
Report an issue: GitHub.