{"record":{"id":"96615c63a64ad430","repo":"BerriAI/litellm","slug":"user-blocked-from-making-llm-api-calls-user-user","errorCode":null,"errorMessage":"User blocked from making LLM API Calls. User={user}","messagePattern":"User blocked from making LLM API Calls\\. User=(.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"enterprise/enterprise_hooks/blocked_user_list.py","lineNumber":78,"sourceCode":"        data: dict,\n        call_type: str,\n    ):\n        try:\n            \"\"\"\n            - check if user id part of call\n            - check if user id part of blocked list\n                - if blocked list is none or user not in blocked list\n                - check if end-user in cache\n                - check if end-user in db\n            \"\"\"\n            self.print_verbose(\"Inside Blocked User List Pre-Call Hook\")\n            if \"user_id\" in data or \"user\" in data:\n                user = data.get(\"user_id\", data.get(\"user\", \"\"))\n                if (\n                    self.blocked_user_list is not None\n                    and user in self.blocked_user_list\n                ):\n                    raise HTTPException(\n                        status_code=400,\n                        detail={\n                            \"error\": f\"User blocked from making LLM API Calls. User={user}\"\n                        },\n                    )\n\n                cache_key = f\"litellm:end_user_id:{user}\"\n                end_user_cache_obj: Optional[LiteLLM_EndUserTable] = cache.get_cache(  # type: ignore\n                    key=cache_key\n                )\n                if end_user_cache_obj is None and self.prisma_client is not None:\n                    # check db\n                    end_user_obj = (\n                        await self.prisma_client.db.litellm_endusertable.find_unique(\n                            where={\"user_id\": user}\n                        )\n                    )\n                    if end_user_obj is None:  # user not in db - assume not blocked","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/enterprise/enterprise_hooks/blocked_user_list.py#L60-L96","documentation":"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.","triggerScenarios":"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\", \"\")).","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"blocked = set(load_blocked_users())\nuser_id = payload.get(\"user_id\") or payload.get(\"user\")\nif user_id in blocked:\n    raise UserBlockedError(user_id)  # fail before spending a round trip","typeGuard":null,"tryCatchPattern":"try:\n    resp = client.chat.completions.create(..., user=user_id)\nexcept HTTPException as e:\n    if e.status_code == 400 and \"User blocked\" in str(e.detail):\n        mark_user_blocked_locally(user_id)  # stop sending for this user\n    raise","preventionTips":["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."],"tags":["enterprise","blocked-users","access-control","http-400","pre-call-hook"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}