BerriAI/litellm · warning · HTTPException
User blocked from making LLM API Calls. User={user}
Error message
User blocked from making LLM API Calls. User={user} What it means
Raised as HTTPException 400 by the BlockedUserList async_pre_call_hook when the request's user/user_id (from the request body) is present in the statically configured blocked_user_list. This is an intentional access-control rejection at the pre-call stage, before any LLM call is made.
Source
Thrown at enterprise/enterprise_hooks/blocked_user_list.py:78
data: dict,
call_type: str,
):
try:
"""
- check if user id part of call
- check if user id part of blocked list
- if blocked list is none or user not in blocked list
- check if end-user in cache
- check if end-user in db
"""
self.print_verbose("Inside Blocked User List Pre-Call Hook")
if "user_id" in data or "user" in data:
user = data.get("user_id", data.get("user", ""))
if (
self.blocked_user_list is not None
and user in self.blocked_user_list
):
raise HTTPException(
status_code=400,
detail={
"error": f"User blocked from making LLM API Calls. User={user}"
},
)
cache_key = f"litellm:end_user_id:{user}"
end_user_cache_obj: Optional[LiteLLM_EndUserTable] = cache.get_cache( # type: ignore
key=cache_key
)
if end_user_cache_obj is None and self.prisma_client is not None:
# check db
end_user_obj = (
await self.prisma_client.db.litellm_endusertable.find_unique(
where={"user_id": user}
)
)
if end_user_obj is None: # user not in db - assume not blockedView on GitHub (pinned to 6c2dcb801b)
Solutions
- The request is blocked by policy — the end user must be unblocked by the admin (remove their ID from blocked_user_list) or the request must use a different, permitted user identifier.
- Admins: verify the entry in blocked_user_list matches exactly (no whitespace/newline artifacts from the file — trailing newlines create empty or mismatched entries).
- Client side: catch the 400 and stop retrying — retries will not succeed while blocked.
Defensive patterns
Strategy: try-catch
Validate before calling
blocked = set(load_blocked_users())
user_id = payload.get("user_id") or payload.get("user")
if user_id in blocked:
raise UserBlockedError(user_id) # fail before spending a round trip Try / catch
try:
resp = client.chat.completions.create(..., user=user_id)
except HTTPException as e:
if e.status_code == 400 and "User blocked" in str(e.detail):
mark_user_blocked_locally(user_id) # stop sending for this user
raise Prevention
- Sync the proxy blocklist into the client's user-management state.
- Strip trailing newlines from blocklist files (file-split entries keep whitespace).
- Never auto-retry 400 block rejections with the same user ID.
- Audit blocked-user changes via the proxy admin API instead of ad-hoc file edits.
When it happens
Trigger: A /chat/completions (or similar) request whose body contains "user" or "user_id" equal to an entry in blocked_users.txt / the configured list. The check is an exact membership test on data.get("user_id", data.get("user", "")).
Common situations: A deactivated user or flagged end-user still has valid application credentials and keeps sending traffic; blocklist updated to include the user and their next request is rejected; test scripts hardcoding a now-blocked user ID.
Related errors
- Keyword banned. Keyword={word}
- File not found. blocked_user_list={blocked_user_list}
- An error occurred: {str(e)}, blocked_user_list={blocked_user
- Violated content safety policy. Category={category}
- Violated content safety policy
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/96615c63a64ad430.
Report an issue: GitHub.