{"record":{"id":"f37c472369d29832","repo":"BerriAI/litellm","slug":"either-key-or-key-alias-must-be-provided-f37c47","errorCode":null,"errorMessage":"either key or key_alias must be provided","messagePattern":"either key or key_alias must be provided","errorType":"exception","errorClass":"ProxyException","httpStatus":400,"severity":"error","filePath":"litellm/proxy/management_endpoints/key_management_endpoints.py","lineNumber":2182,"sourceCode":"    if token is not None:\n        hashed_token: Final = _hash_token_if_needed(token=token)\n\n        existing_key_row: Final[LiteLLM_VerificationToken | None] = await _prisma_table(\n            VerificationTokenRepository(prisma_client)\n        ).find_unique(where={\"token\": hashed_token})\n\n        if existing_key_row is None:\n            raise ProxyException(\n                message=\"Key not found.\",\n                type=ProxyErrorTypes.not_found_error,\n                param=\"key\",\n                code=status.HTTP_404_NOT_FOUND,\n            )\n\n        return existing_key_row\n\n    if key_alias is None:\n        raise ProxyException(\n            message=\"either key or key_alias must be provided\",\n            type=ProxyErrorTypes.bad_request_error,\n            param=\"key\",\n            code=status.HTTP_400_BAD_REQUEST,\n        )\n\n    rows: list[LiteLLM_VerificationToken] = await _prisma_table(VerificationTokenRepository(prisma_client)).find_many(\n        where={\"key_alias\": key_alias}, take=2\n    )\n\n    if len(rows) == 0:\n        raise ProxyException(\n            message=f\"Key not found. No key with key_alias='{key_alias}'.\",\n            type=ProxyErrorTypes.not_found_error,\n            param=\"key_alias\",\n            code=status.HTTP_404_NOT_FOUND,\n        )\n","sourceCodeStart":2164,"sourceCodeEnd":2200,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/management_endpoints/key_management_endpoints.py#L2164-L2200","documentation":"_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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\nawait client.post(\"/key/update\", json={\"max_budget\": 100})\n\n# after\nawait client.post(\"/key/update\", json={\"key\": \"sk-abc123\", \"max_budget\": 100})","handlingStrategy":"validation","validationCode":"if not payload.get(\"key\") and not payload.get(\"key_alias\"):\n    raise ValueError(\"update payload must include 'key' or 'key_alias'\")\nawait client.post(\"/key/update\", json=payload)","typeGuard":"def has_key_identifier(p: dict) -> bool:\n    return bool(p.get(\"key\") or p.get(\"key_alias\"))","tryCatchPattern":"try:\n    r = await client.post(\"/key/update\", json=payload)\nexcept httpx.HTTPStatusError as e:\n    if e.response.status_code == 400 and \"either key or key_alias\" in e.response.text:\n        payload[\"key\"] = resolve_key()  # attach the identifier and resend\n        r = await client.post(\"/key/update\", json=payload)\n    else:\n        raise","preventionTips":["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"],"tags":["litellm","proxy","validation","missing-parameter","key-update"],"backgroundTag":"missing-required-parameter","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}