BerriAI/litellm · warning · ValueError
Invalid request type
Error message
Invalid request type
What it means
POST /key/delete dispatches on which field of the KeyRequest body is populated: data.keys triggers token deletion, data.key_aliases triggers alias deletion. If both are falsy the handler raises this ValueError ('Invalid request type'), which the endpoint wrapper converts into an error response. In other words: the delete request carried neither keys nor key_aliases.
Source
Thrown at litellm/proxy/management_endpoints/key_management_endpoints.py:3420
tokens=data.keys,
user_api_key_cache=user_api_key_cache,
user_api_key_dict=user_api_key_dict,
litellm_changed_by=litellm_changed_by,
)
num_keys_to_be_deleted = len(data.keys)
deleted_keys = data.keys
elif data.key_aliases:
number_deleted_keys, _keys_being_deleted = await delete_key_aliases(
key_aliases=data.key_aliases,
prisma_client=prisma_client,
user_api_key_cache=user_api_key_cache,
user_api_key_dict=user_api_key_dict,
litellm_changed_by=litellm_changed_by,
)
num_keys_to_be_deleted = len(data.key_aliases)
deleted_keys = data.key_aliases
else:
raise ValueError("Invalid request type")
if number_deleted_keys is None:
raise ProxyException(
message="Failed to delete keys got None response from delete_verification_token",
type=ProxyErrorTypes.internal_server_error,
param="keys",
code=status.HTTP_500_INTERNAL_SERVER_ERROR,
)
verbose_proxy_logger.debug("/key/delete - deleted_keys=%s", number_deleted_keys)
try:
assert num_keys_to_be_deleted == len(deleted_keys)
except Exception:
raise HTTPException(
status_code=400,
detail={
"error": f"Not all keys passed in were deleted. This probably means you don't have access to delete all the keys passed in. Keys passed in={num_keys_to_be_deleted}, Deleted keys ={number_deleted_keys}"
},View on GitHub (pinned to 77b7c6c40c)
Solutions
- Send {"keys": ["sk-..."]} (list of key tokens) to delete by token, or {"key_aliases": ["alias1"]} to delete by alias.
- Check for typos in the field name — only `keys` and `key_aliases` are recognized.
- Skip the API call when your computed delete list is empty.
Example fix
# before
client.post("/key/delete", json={"key": key_to_delete})
# after
client.post("/key/delete", json={"keys": [key_to_delete]}) Defensive patterns
Strategy: validation
Validate before calling
def build_delete_body(keys: list[str] | None = None, key_aliases: list[str] | None = None) -> dict:
if keys:
return {"keys": keys}
if key_aliases:
return {"key_aliases": key_aliases}
raise ValueError("/key/delete requires non-empty 'keys' or 'key_aliases'") Type guard
def is_valid_delete_request(keys: list[str] | None, key_aliases: list[str] | None) -> bool:
return bool(keys) or bool(key_aliases) Prevention
- Route all deletes through one builder that refuses empty payloads.
- Remember the accepted fields are exactly `keys` (tokens) and `key_aliases` — never `key` or `key_ids`.
- Add a schema check (pydantic/jsonschema) on outgoing admin payloads in integration tests.
When it happens
Trigger: POST /key/delete with an empty body, {}, {"keys": []} and no aliases, or a payload using a wrong field name (e.g. {"key": "sk-..."} singular, or key_ids).
Common situations: Client code building the JSON dynamically and emitting {} when nothing to delete; field-name drift after upgrading from an older/newer API that used a different property; manual curl missing the -d body.
Understand the failure class
Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.
Related errors
- key_ids must be provided when all_keys_in_team is False
- Malformed request. No keys passed in.
- Maximum {MAX_BATCH_SIZE} keys can be updated at once. Found
- For SAP Masking Module Config you must provide 'providers'.
- For using SAP Filtering Module you must provide at least one
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/27ea5fa0e92840d1.
Report an issue: GitHub.