BerriAI/litellm · error · HTTPException
User ID not found in token
Error message
User ID not found in token
What it means
Returned (400) by the store-BYOK-credential endpoint when user_api_key_dict.user_id is empty after the server is authorized. The endpoint needs a concrete user to scope the credential to (store_user_credential(prisma_client, user_id, server_id, ...)), so a key that authenticates but is not bound to a user — typically the master key or a bare virtual key — cannot store per-user credentials.
Source
Thrown at litellm/proxy/management_endpoints/mcp_management_endpoints.py:2054
response_model=MCPUserCredentialResponse,
)
@management_endpoint_wrapper
async def store_mcp_user_credential(
server_id: str,
payload: MCPUserCredentialRequest,
user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth),
):
"""Store a BYOK credential for the calling user."""
prisma_client: Final = get_prisma_client_or_throw("Database not connected. Connect a database to your proxy")
mcp_server: Final = await _authorize_and_fetch_mcp_server(prisma_client, user_api_key_dict, server_id)
if not getattr(mcp_server, "is_byok", False):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail={"error": "This MCP server does not support BYOK credentials"},
)
user_id: Final = user_api_key_dict.user_id or ""
if not user_id:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail={"error": "User ID not found in token"},
)
if payload.save:
await store_user_credential(prisma_client, user_id, server_id, payload.credential)
from litellm.proxy._experimental.mcp_server.server import (
_invalidate_byok_cred_cache,
)
_invalidate_byok_cred_cache(user_id, server_id)
return MCPUserCredentialResponse(server_id=server_id, has_credential=True)
# save=False: credential not persisted
return MCPUserCredentialResponse(server_id=server_id, has_credential=False)
@router.delete(
"/server/{server_id}/user-credential",
description="Delete the calling user's stored API key for a BYOK MCP server",
dependencies=[Depends(user_api_key_auth)],View on GitHub (pinned to 77b7c6c40c)
Solutions
- Use a key that is bound to a user (create the virtual key with a user / user_id) and retry.
- Check the calling key first via /key/info and confirm its user_id is set.
- For UI flows, log in as the user so the session token carries the user binding.
Example fix
# before
requests.post(f"{PROXY}/v1/mcp/server/{server_id}/credentials", headers={"Authorization": f"Bearer {os.environ['LITELLM_MASTER_KEY']}"}, json=payload)
# after: use a user-bound virtual key
requests.post(f"{PROXY}/v1/mcp/server/{server_id}/credentials", headers={"Authorization": f"Bearer {USER_VIRTUAL_KEY}"}, json=payload) Defensive patterns
Strategy: validation
Validate before calling
info = requests.get(f"{PROXY}/key/info", headers=AUTH, params={"key": KEY}).json()
user_id = info.get("key_info", info).get("user_id")
if not user_id:
raise ValueError("use a virtual key created with user_id for BYOK credential storage") Type guard
def key_bound_to_user(key_info: dict) -> bool:
return bool(key_info.get("user_id")) Try / catch
try:
store_credential(server_id, payload)
except HTTPError as e:
if e.response.status_code == 400 and "User ID not found" in e.response.text:
raise ValueError("switch to the user's own virtual key (it must carry user_id)")
raise Prevention
- Never use the master key for per-user endpoints.
- Issue virtual keys with an explicit user binding when BYOK is enabled.
When it happens
Trigger: Calling the credential store endpoint with the proxy master key; using a virtual key created without a user binding; service-to-service keys that have role but no user_id.
Common situations: Scripts authenticating with LITELLM_MASTER_KEY for everything; keys generated before user assignment policies existed; migrating from shared keys to per-user BYOK without re-issuing keys.
Related errors
- byok_auth_required
- This MCP server does not support BYOK credentials
- Cloudflare Exception - {original_exception.message}
- CohereException - {original_exception.message}
- OpenRouter API key is required. Set OPENROUTER_API_KEY envir
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/aee0a65d85636d43.
Report an issue: GitHub.