BerriAI/litellm · error · ProxyException

End User Id={data.user_id} does not exist in db

Error message

End User Id={data.user_id} does not exist in db

What it means

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.

Source

Thrown at litellm/proxy/management_endpoints/customer_endpoints.py:642

            raise Exception("Not connected to DB!")

        # get non default values for key
        non_default_values: Final = dict[str, object]()
        for k, v in data_json.items():
            if v is not None and v not in (
                [],
                {},
                0,
            ):  # models default to [], spend defaults to 0, we should not reset these values
                non_default_values[k] = v

        ## Get end user table data ##
        end_user_table_data: Final = await _typed_table(EndUserRepository(prisma_client)).find_first(
            where={"user_id": data.user_id}, include={"litellm_budget_table": True}
        )

        if end_user_table_data is None:
            raise ProxyException(
                message=f"End User Id={data.user_id} does not exist in db",
                type="not_found",
                code=404,
                param="user_id",
            )

        end_user_table_data_typed: Final = LiteLLM_EndUserTable.model_validate(end_user_table_data.model_dump())

        ## Get budget table data ##
        end_user_budget_table: Final = end_user_table_data_typed.litellm_budget_table

        ## Get all params for budget table ##
        budget_table_data: Final = dict[str, object]()
        update_end_user_table_data: Final = dict[str, object]()
        for k, v in non_default_values.items():
            # budget_id is for linking to existing budget, not for creating new budget
            if k == "budget_id":
                update_end_user_table_data[k] = v

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Fetch the current id first (GET /customer/info or /customer/list) and send that as user_id
  2. If the customer should not exist yet, create it with POST /customer/new instead of updating
  3. To change a customer's id: create the new customer, migrate references, then delete the old one

Example fix

# before
update_customer({"user_id": "new-id", ...})   # looking up by the NEW id -> 404

# after
update_customer({"user_id": "existing-id", ...})  # update by the id that already exists
Defensive patterns

Strategy: validation

Validate before calling

import httpx


def customer_exists(base: str, headers: dict, user_id: str) -> bool:
    r = httpx.get(f"{base}/customer/info", params={"end_user_id": user_id}, headers=headers)
    return r.status_code == 200

Try / catch

try:
    r = httpx.post(f"{base}/customer/update", json=payload, headers=headers)
except httpx.HTTPStatusError as e:
    if e.response.status_code == 404 and "does not exist" in e.response.text:
        r = httpx.post(f"{base}/customer/new", json=payload, headers=headers)  # upsert fallback
        return r.json()
    raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/7932a8e2e5d0ec7d. Report an issue: GitHub.