{"record":{"id":"7932a8e2e5d0ec7d","repo":"BerriAI/litellm","slug":"end-user-id-data-user-id-does-not-exist-in-db","errorCode":null,"errorMessage":"End User Id={data.user_id} does not exist in db","messagePattern":"End User Id=(.+?) does not exist in db","errorType":"http","errorClass":"ProxyException","httpStatus":404,"severity":"error","filePath":"litellm/proxy/management_endpoints/customer_endpoints.py","lineNumber":642,"sourceCode":"            raise Exception(\"Not connected to DB!\")\n\n        # get non default values for key\n        non_default_values: Final = dict[str, object]()\n        for k, v in data_json.items():\n            if v is not None and v not in (\n                [],\n                {},\n                0,\n            ):  # models default to [], spend defaults to 0, we should not reset these values\n                non_default_values[k] = v\n\n        ## Get end user table data ##\n        end_user_table_data: Final = await _typed_table(EndUserRepository(prisma_client)).find_first(\n            where={\"user_id\": data.user_id}, include={\"litellm_budget_table\": True}\n        )\n\n        if end_user_table_data is None:\n            raise ProxyException(\n                message=f\"End User Id={data.user_id} does not exist in db\",\n                type=\"not_found\",\n                code=404,\n                param=\"user_id\",\n            )\n\n        end_user_table_data_typed: Final = LiteLLM_EndUserTable.model_validate(end_user_table_data.model_dump())\n\n        ## Get budget table data ##\n        end_user_budget_table: Final = end_user_table_data_typed.litellm_budget_table\n\n        ## Get all params for budget table ##\n        budget_table_data: Final = dict[str, object]()\n        update_end_user_table_data: Final = dict[str, object]()\n        for k, v in non_default_values.items():\n            # budget_id is for linking to existing budget, not for creating new budget\n            if k == \"budget_id\":\n                update_end_user_table_data[k] = v","sourceCodeStart":624,"sourceCodeEnd":660,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/management_endpoints/customer_endpoints.py#L624-L660","documentation":"Before mutating anything, POST /customer/update fetches the row for data.user_id (find_first with include of the budget table). If no row matches, it raises a 404 not_found ProxyException with the passed user_id (param=user_id) - the customer must already exist to be updated.","triggerScenarios":"POST /customer/update with a user_id that does not exist: never created, previously deleted via /customer/delete, or a rename attempt where the caller sends the intended NEW id instead of the current one.","commonSituations":"Rename-by-update attempts (the lookup keys on the passed id, so a new id finds nothing); stale ids after re-importing or migrating customers; concurrent deletion between read and update.","solutions":["Fetch the current id first (GET /customer/info or /customer/list) and send that as user_id","If the customer should not exist yet, create it with POST /customer/new instead of updating","To change a customer's id: create the new customer, migrate references, then delete the old one"],"exampleFix":"# before\nupdate_customer({\"user_id\": \"new-id\", ...})   # looking up by the NEW id -> 404\n\n# after\nupdate_customer({\"user_id\": \"existing-id\", ...})  # update by the id that already exists","handlingStrategy":"validation","validationCode":"import httpx\n\n\ndef customer_exists(base: str, headers: dict, user_id: str) -> bool:\n    r = httpx.get(f\"{base}/customer/info\", params={\"end_user_id\": user_id}, headers=headers)\n    return r.status_code == 200","typeGuard":null,"tryCatchPattern":"try:\n    r = httpx.post(f\"{base}/customer/update\", json=payload, headers=headers)\nexcept httpx.HTTPStatusError as e:\n    if e.response.status_code == 404 and \"does not exist\" in e.response.text:\n        r = httpx.post(f\"{base}/customer/new\", json=payload, headers=headers)  # upsert fallback\n        return r.json()\n    raise","preventionTips":["Always update by the id returned from /customer/info or /customer/list, never a hand-typed one","Remember /customer/update cannot rename - plan create-migrate-delete for id changes","Handle 404 on update as 'create instead' or 'skip' explicitly in sync jobs"],"tags":["litellm","not-found","customer-management","http-404","rename"],"backgroundTag":"resource-not-found","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}