BerriAI/litellm · error · ProxyException
Invalid key format.
Error message
Invalid key format.
What it means
POST /key/block validates data.key with is_valid_api_key before touching the database. A valid value is either a raw 'sk-...' key matching ^sk-[A-Za-z0-9_-]+$ or an already-hashed 64-character hex token ^[a-fA-F0-9]{64}$, with total length between 3 and 100. Anything else (empty string, keys with dots/slashes, other prefixes like 'pk-') gets a 400 ProxyException with param='key'.
Source
Thrown at litellm/proxy/management_endpoints/key_management_endpoints.py:6230
Note: This is an admin-only endpoint. Only proxy admins, team admins, or org admins can block keys.
"""
from litellm.proxy.management_helpers.audit_logs import (
get_audit_log_changed_by,
)
from litellm.proxy.proxy_server import (
create_audit_log_for_update,
hash_token,
litellm_proxy_admin_name,
prisma_client,
proxy_logging_obj,
user_api_key_cache,
)
if prisma_client is None:
raise Exception(f"{CommonProxyErrors.db_not_connected_error.value}")
if not is_valid_api_key(data.key):
raise ProxyException(
message="Invalid key format.",
type=ProxyErrorTypes.bad_request_error,
param="key",
code=status.HTTP_400_BAD_REQUEST,
)
if data.key.startswith("sk-"):
hashed_token = hash_token(token=data.key)
else:
hashed_token = data.key
# Admin-only: only proxy admins, team admins, or org admins can block keys
await _check_key_admin_access(
user_api_key_dict=user_api_key_dict,
hashed_token=hashed_token,
prisma_client=prisma_client,
user_api_key_cache=user_api_key_cache,
route="/key/block",
)View on GitHub (pinned to 77b7c6c40c)
Solutions
- Send the raw key exactly as returned at creation time ('sk-' followed by [A-Za-z0-9_-] only)
- Or send the 64-character lowercase/uppercase hex hash (the 'token' field from /key/list) — never a partially copied one
- Do not send aliases, display names, or other providers' key formats to /key/block
- Check for invisible characters if a visually correct key still fails: printf '%s' "$KEY" | wc -c must equal the expected length
Example fix
# before
await client.post('/key/block', json={'key': 'pk-live-abc123'}) # 400: Invalid key format.
# after
await client.post('/key/block', json={'key': 'sk-XyZ_123-abc'}) # raw key (hashed server-side)
# or
await client.post('/key/block', json={'key': key_row['token']}) # 64-hex hash from /key/list Defensive patterns
Strategy: type-guard
Validate before calling
import re
RAW_KEY_RE = re.compile(r'^sk-[A-Za-z0-9_-]+$')
HASH_RE = re.compile(r'^[a-fA-F0-9]{64}$')
def is_blockable_key(key: str) -> bool:
"""Mirror of litellm.proxy.utils.is_valid_api_key."""
return isinstance(key, str) and 3 <= len(key) <= 100 and bool(
RAW_KEY_RE.match(key) or HASH_RE.match(key)
) Type guard
from typing import TypeGuard
def is_blockable_key(key: object) -> TypeGuard[str]:
return (
isinstance(key, str)
and 3 <= len(key) <= 100
and bool(RAW_KEY_RE.match(key) or HASH_RE.match(key))
) Try / catch
if not is_blockable_key(tok):
raise ValueError(f'refusing to call /key/block with malformed key: {tok[:6]}...')
try:
await client.post('/key/block', json={'key': tok})
except httpx.HTTPStatusError as e:
if e.response.status_code == 400 and 'Invalid key format' in e.response.text:
raise ValueError('key format rejected by server') from e
raise Prevention
- Never derive the value — use the token returned by /key/generate or /key/list verbatim
- Store keys in secrets managers, not config files that may alter characters
- Checksum the length client-side: raw sk- keys and 64-hex hashes have predictable shapes
When it happens
Trigger: Sending 'pk-...' or other non-sk- prefixed strings (which are then assumed to be hashes and fail the 64-hex check); sending the hashed token with uppercase HEX beyond a-f (invalid hex); sending keys containing '.', ':', or whitespace; sending a truncated hash.
Common situations: Copy-paste truncation of long hashes; mixing up LiteLLM virtual keys with provider keys of a different prefix; passing the key_alias or key display name instead of the actual token; form inputs that trim/alter characters.
Related errors
- Invalid budget_duration '{budget_duration}'. Use a format li
- Invalid sort order. Must be 'asc' or 'desc'
- Key not found: {hashed_token}
- Invalid key_alias format. Must be 2-255 characters, start/en
- Invalid model_max_budget: {e}. Example of valid model_max_bu
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/93fd67092774bb84.
Report an issue: GitHub.