BerriAI/litellm · error · HTTPException
Key not found: {hashed_token}
Error message
Key not found: {hashed_token} What it means
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.
Source
Thrown at litellm/proxy/management_endpoints/key_management_endpoints.py:6157
Check that the caller has admin privileges for the target key.
Allowed callers:
- Proxy admin
- Team admin for the key's team
- Org admin for the key's team's organization
Raises HTTPException(403) if the caller is not authorized.
"""
if user_api_key_dict.user_role == LitellmUserRoles.PROXY_ADMIN.value:
return
# Look up the target key to find its team
target_key_row: Final = await _prisma_table(VerificationTokenRepository(prisma_client)).find_unique(
where={"token": hashed_token}
)
if target_key_row is None:
raise HTTPException(
status_code=404,
detail={"error": f"Key not found: {hashed_token}"},
)
# If the key belongs to a team, check team admin / org admin
if target_key_row.team_id:
team_obj: Final = await get_team_object(
team_id=target_key_row.team_id,
prisma_client=prisma_client,
user_api_key_cache=user_api_key_cache,
check_db_only=True,
)
if team_obj is not None:
if _is_user_team_admin(user_api_key_dict=user_api_key_dict, team_obj=team_obj):
return
if await _is_user_org_admin_for_team(user_api_key_dict=user_api_key_dict, team_obj=team_obj):
return
View on GitHub (pinned to 77b7c6c40c)
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
Example fix
# before
await client.post('/key/block', json={'key': truncated_hash}) # 404: Key not found: <hash>
# after
info = await client.get('/key/info', params={'key': truncated_hash})
if info.status_code == 404:
pass # already deleted; nothing to block
else:
await client.post('/key/block', json={'key': info.json()['token']}) Defensive patterns
Strategy: try-catch
Validate before calling
async def key_exists(client: httpx.AsyncClient, hashed_token: str) -> bool:
r = await client.get('/key/info', params={'key': hashed_token})
return r.status_code == 200 Try / catch
try:
await client.post('/key/block', json={'key': tok})
except httpx.HTTPStatusError as e:
if e.response.status_code == 404:
pass # key already deleted: desired end state, nothing to block
elif e.response.status_code == 403:
raise PermissionError('caller is not proxy/team/org admin for this key')
else:
raise Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Skill not found: {skill_id}
- Only proxy admins can set `allowed_passthrough_routes` on a
- Only proxy admins, team admins, or org admins can call {rout
- Invalid key format.
- Unable to record skill ownership: caller has no identity sco
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/84651eaa50b56779.
Report an issue: GitHub.