{"record":{"id":"202d53553f7bd57a","repo":"BerriAI/litellm","slug":"end-user-id-s-do-not-exist-in-db","errorCode":null,"errorMessage":"End User Id(s)={} do not exist in db","messagePattern":"End User Id\\(s\\)=(.+?) do not exist in db","errorType":"http","errorClass":"ProxyException","httpStatus":404,"severity":"error","filePath":"litellm/proxy/management_endpoints/customer_endpoints.py","lineNumber":783,"sourceCode":"    ```\n    \"\"\"\n    from litellm.proxy.proxy_server import prisma_client\n\n    try:\n        if prisma_client is None:\n            raise Exception(\"Not connected to DB!\")\n\n        verbose_proxy_logger.debug(\"/customer/delete: Received data = %s\", data)\n        if data.user_ids is not None and isinstance(data.user_ids, list) and len(data.user_ids) > 0:\n            # First check if all users exist\n            existing_users: Final = await _typed_table(EndUserRepository(prisma_client)).find_many(\n                where={\"user_id\": {\"in\": data.user_ids}}\n            )\n            existing_user_ids: Final = {user.user_id for user in existing_users}\n            missing_user_ids: Final = [user_id for user_id in data.user_ids if user_id not in existing_user_ids]\n\n            if missing_user_ids:\n                raise ProxyException(\n                    message=\"End User Id(s)={} do not exist in db\".format(\", \".join(missing_user_ids)),\n                    type=\"not_found\",\n                    code=404,\n                    param=\"user_ids\",\n                )\n\n            # All users exist, proceed with deletion\n            response: Final = await _typed_table(EndUserRepository(prisma_client)).delete_many(\n                where={\"user_id\": {\"in\": data.user_ids}}\n            )\n            verbose_proxy_logger.debug(\"received response from updating prisma client. response=%s\", response)\n\n            await _evict_end_user_cache_keys(_end_user_cache_keys(data.user_ids))\n\n            return DeleteCustomersResponse(\n                deleted_customers=response,\n                message=\"Successfully deleted customers with ids: \" + str(data.user_ids),\n            )","sourceCodeStart":765,"sourceCodeEnd":801,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/management_endpoints/customer_endpoints.py#L765-L801","documentation":"POST /customer/delete pre-fetches all requested user_ids with find_many; if any id has no row it returns a 404 not_found ProxyException (param=user_ids) listing exactly which ids do not exist, and deletes nothing - delete_many only runs when every requested id resolves.","triggerScenarios":"POST /customer/delete with a batch containing at least one unknown id: deleted by an earlier run, never created, or differing by casing/whitespace.","commonSituations":"Re-running non-idempotent delete scripts whose previous attempt removed part of the batch; concurrent deletes from two jobs; batch payloads assembled from stale exports.","solutions":["Reconcile first: GET /customer/list and delete only ids that still exist","Make delete jobs idempotent - treat already-missing ids as successfully deleted","Retry with the valid subset: the error message itself prints the missing ids to drop"],"exampleFix":"# before\nresp = post(\"/customer/delete\", {\"user_ids\": [\"a\", \"b\", \"c\"]})  # \"c\" already gone -> 404, nothing deleted\n\n# after\nmissing = {\"c\"}\nresp = post(\"/customer/delete\", {\"user_ids\": [i for i in ids if i not in missing]})","handlingStrategy":"validation","validationCode":"import httpx\n\n\ndef split_deletable(base: str, headers: dict, user_ids: list[str]) -> tuple[list[str], list[str]]:\n    listed = {c[\"user_id\"] for c in httpx.get(f\"{base}/customer/list\", headers=headers).json()}\n    return [i for i in user_ids if i in listed], [i for i in user_ids if i not in listed]","typeGuard":null,"tryCatchPattern":"try:\n    r = httpx.post(f\"{base}/customer/delete\", json={\"user_ids\": ids}, headers=headers)\nexcept httpx.HTTPStatusError as e:\n    if e.response.status_code == 404 and \"do not exist\" in e.response.text:\n        missing = e.response.json()[\"detail\"][\"error\"].split(\"End User Id(s)=\")[1].split(\" do not\")[0]\n        ids = [i for i in ids if i not in missing.split(\", \")]\n        return httpx.post(f\"{base}/customer/delete\", json={\"user_ids\": ids}, headers=headers)\n    raise","preventionTips":["Diff the delete batch against /customer/list before sending it","Log and ignore 404 'do not exist' in idempotent cleanup pipelines","Avoid running two concurrent delete jobs over the same customer set"],"tags":["litellm","not-found","customer-management","http-404","batch-delete"],"backgroundTag":"resource-not-found","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}