BerriAI/litellm · error · ValueError

Failed updating customer data. User ID does not exist passed

Error message

Failed updating customer data. User ID does not exist passed user_id={data.user_id}

What it means

POST /customer/update writes with where={"user_id": data.user_id} and expects Prisma's update to return the updated record. If no row matches - commonly because the code also assigns data.user_id into the update payload, so sending a NEW id as user_id matches nothing - update returns None and the endpoint raises ValueError('Failed updating customer data...'), which handle_exception_on_proxy converts to HTTP 500.

Source

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

        # Ensure object_permission is not in the update data
        # It should have been converted to object_permission_id by handle_update_object_permission_common
        if "object_permission" in update_end_user_table_data:
            verbose_proxy_logger.warning(
                "object_permission still in update_end_user_table_data: %s",
                update_end_user_table_data.get("object_permission"),
            )
            update_end_user_table_data.pop("object_permission", None)

        if data.user_id is not None and len(data.user_id) > 0:
            update_end_user_table_data["user_id"] = data.user_id
            verbose_proxy_logger.debug("In update customer, user_id condition block.")
            response: Final = await _typed_table(EndUserRepository(prisma_client)).update(
                where={"user_id": data.user_id},
                data=update_end_user_table_data,
                include={"litellm_budget_table": True, "object_permission": True},
            )
            if response is None:
                raise ValueError(f"Failed updating customer data. User ID does not exist passed user_id={data.user_id}")
            verbose_proxy_logger.debug("received response from updating prisma client. response=%s", response)

            await _evict_end_user_cache_keys(_end_user_cache_keys((data.user_id,)))

            return _to_customer_response(response)
        else:
            raise ValueError(f"user_id is required, passed user_id = {data.user_id}")

        # update based on remaining passed in values

    except Exception as e:
        verbose_proxy_logger.exception("litellm.proxy.proxy_server.update_end_user(): Exception occured - %s", e)
        raise handle_exception_on_proxy(e)


@router.post(
    "/customer/delete",
    tags=["Customer Management"],

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Send the EXISTING user_id in the request body; confirm it with GET /customer/info first
  2. To change a customer's id: create the new customer, migrate references, delete the old one
  3. Treat this 500 as a not-found signal in callers - it indicates no row matched, not a server outage

Example fix

# before
resp = update_customer({"user_id": "renamed-id", "blocked": True})   # no row with "renamed-id" -> 500

# after
resp = update_customer({"user_id": "original-id", "blocked": True})  # existing row updated
Defensive patterns

Strategy: validation

Validate before calling

import httpx


def safe_update(base: str, headers: dict, payload: dict) -> dict:
    uid = payload["user_id"]
    if httpx.get(f"{base}/customer/info", params={"end_user_id": uid}, headers=headers).status_code != 200:
        raise KeyError(f"customer {uid!r} does not exist; update would 500")
    r = httpx.post(f"{base}/customer/update", json=payload, headers=headers)
    r.raise_for_status()
    return r.json()

Try / catch

try:
    r = httpx.post(f"{base}/customer/update", json=payload, headers=headers)
except httpx.HTTPStatusError as e:
    if e.response.status_code == 500 and "Failed updating customer data" in e.response.text:
        raise LookupError(f"no customer with user_id={payload['user_id']!r}") from e
    raise

Prevention

When it happens

Trigger: POST /customer/update with a user_id that has no existing row: typically a rename attempt passing the new id, or the customer was deleted concurrently before the update landed.

Common situations: Teams try to change a customer's identifier through update and hit this because the where-clause uses the same new id; races where another process deletes the customer between read and write; whitespace-normalized ids that no longer match stored values.

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/1b9caf40b1a53788. Report an issue: GitHub.