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

  1. Send the raw key exactly as returned at creation time ('sk-' followed by [A-Za-z0-9_-] only)
  2. Or send the 64-character lowercase/uppercase hex hash (the 'token' field from /key/list) — never a partially copied one
  3. Do not send aliases, display names, or other providers' key formats to /key/block
  4. 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

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


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