{"record":{"id":"84651eaa50b56779","repo":"BerriAI/litellm","slug":"key-not-found-hashed-token","errorCode":null,"errorMessage":"Key not found: {hashed_token}","messagePattern":"Key not found: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"error","filePath":"litellm/proxy/management_endpoints/key_management_endpoints.py","lineNumber":6157,"sourceCode":"    Check that the caller has admin privileges for the target key.\n\n    Allowed callers:\n    - Proxy admin\n    - Team admin for the key's team\n    - Org admin for the key's team's organization\n\n    Raises HTTPException(403) if the caller is not authorized.\n    \"\"\"\n\n    if user_api_key_dict.user_role == LitellmUserRoles.PROXY_ADMIN.value:\n        return\n\n    # Look up the target key to find its team\n    target_key_row: Final = await _prisma_table(VerificationTokenRepository(prisma_client)).find_unique(\n        where={\"token\": hashed_token}\n    )\n    if target_key_row is None:\n        raise HTTPException(\n            status_code=404,\n            detail={\"error\": f\"Key not found: {hashed_token}\"},\n        )\n\n    # If the key belongs to a team, check team admin / org admin\n    if target_key_row.team_id:\n        team_obj: Final = await get_team_object(\n            team_id=target_key_row.team_id,\n            prisma_client=prisma_client,\n            user_api_key_cache=user_api_key_cache,\n            check_db_only=True,\n        )\n        if team_obj is not None:\n            if _is_user_team_admin(user_api_key_dict=user_api_key_dict, team_obj=team_obj):\n                return\n            if await _is_user_org_admin_for_team(user_api_key_dict=user_api_key_dict, team_obj=team_obj):\n                return\n","sourceCodeStart":6139,"sourceCodeEnd":6175,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/management_endpoints/key_management_endpoints.py#L6139-L6175","documentation":"Thrown from _check_key_admin_access when a NON-proxy-admin caller (e.g. a team admin) invokes /key/block or /key/unblock and the target key cannot be found in the verification token table. The helper needs the key's row to discover its team_id so it can decide team/org admin rights, so a missing row is fatal before the 403 authorization check. Proxy admins never hit this path because the function returns early for them.","triggerScenarios":"A team admin or org admin POSTs /key/block with a key that was already deleted, was never created, or whose hashed token was mistyped. Note the raw sk-... value is hashed upstream, so this usually means the 64-hex hash is wrong (copied truncated, wrong environment's DB).","commonSituations":"Multi-tenant setups where a team admin blocks keys from a stale list fetched minutes earlier and the key was rotated/deleted meanwhile; scripts pointing at the wrong proxy instance (key exists in prod DB but not in staging); passing a display alias instead of the token.","solutions":["Verify the key still exists first: GET /key/info or /key/list with the same hashed token against the same proxy instance","If you meant to pass the raw key, confirm you copied the full 'sk-' value (the server hashes it automatically) — a truncated hash will not match","Treat 404 on block/unblock as idempotent success if the goal is 'make sure this key cannot be used'","If you are a proxy admin and still see this, check you are calling the right route — the lookup only runs for non-admin callers"],"exampleFix":"# before\nawait client.post('/key/block', json={'key': truncated_hash})      # 404: Key not found: <hash>\n# after\ninfo = await client.get('/key/info', params={'key': truncated_hash})\nif info.status_code == 404:\n    pass  # already deleted; nothing to block\nelse:\n    await client.post('/key/block', json={'key': info.json()['token']})","handlingStrategy":"try-catch","validationCode":"async def key_exists(client: httpx.AsyncClient, hashed_token: str) -> bool:\n    r = await client.get('/key/info', params={'key': hashed_token})\n    return r.status_code == 200","typeGuard":null,"tryCatchPattern":"try:\n    await client.post('/key/block', json={'key': tok})\nexcept httpx.HTTPStatusError as e:\n    if e.response.status_code == 404:\n        pass   # key already deleted: desired end state, nothing to block\n    elif e.response.status_code == 403:\n        raise PermissionError('caller is not proxy/team/org admin for this key')\n    else:\n        raise","preventionTips":["Always operate on the 'token' value freshly fetched from /key/list, not a cached one","Treat block/unblock as idempotent: 404 means the key is already unusable","Confirm which proxy instance/DB you are talking to before admin operations"],"tags":["keys","not-found","authorization","litellm-proxy","block"],"backgroundTag":"resource-not-found","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}