BerriAI/litellm · error · ValueError

user_id is required, passed user_id = {data.user_ids}

Error message

user_id is required, passed user_id = {data.user_ids}

What it means

POST /customer/delete requires user_ids to be a non-empty list; otherwise the endpoint raises ValueError (note the message says 'user_id' although the field is user_ids), which handle_exception_on_proxy converts to HTTP 500. Like the update route, a client payload mistake surfaces as a server error code.

Source

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

                    type="not_found",
                    code=404,
                    param="user_ids",
                )

            # All users exist, proceed with deletion
            response: Final = await _typed_table(EndUserRepository(prisma_client)).delete_many(
                where={"user_id": {"in": data.user_ids}}
            )
            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_ids))

            return DeleteCustomersResponse(
                deleted_customers=response,
                message="Successfully deleted customers with ids: " + str(data.user_ids),
            )
        else:
            raise ValueError(f"user_id is required, passed user_id = {data.user_ids}")

        # update based on remaining passed in values
    except Exception as e:
        verbose_proxy_logger.error("litellm.proxy.proxy_server.delete_end_user(): Exception occured - %s", e)
        raise handle_exception_on_proxy(e)


@router.get(
    "/customer/list",
    tags=["Customer Management"],
    dependencies=[Depends(user_api_key_auth)],
    response_model=list[CustomerResponse],
)
@router.get(
    "/end_user/list",
    tags=["Customer Management"],
    include_in_schema=False,
    dependencies=[Depends(user_api_key_auth)],

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Skip the API call entirely when the candidate list is empty
  2. Require a non-empty user_ids array in the request-building code
  3. Classify this 500 as a client payload bug, not a proxy fault

Example fix

# before
resp = post("/customer/delete", {"user_ids": []})   # -> 500 ValueError via handler

# after
if ids:
    resp = post("/customer/delete", {"user_ids": ids})
Defensive patterns

Strategy: validation

Validate before calling

def delete_payload_valid(payload: dict) -> bool:
    ids = payload.get("user_ids")
    return isinstance(ids, list) and len(ids) > 0

Type guard

from typing import TypeGuard


def has_non_empty_user_ids(payload: dict) -> TypeGuard[dict]:
    """Narrows to payloads safe to send to POST /customer/delete."""
    ids = payload.get("user_ids")
    return isinstance(ids, list) and len(ids) > 0 and all(isinstance(i, str) and i for i in ids)

Try / catch

try:
    r = httpx.post(f"{base}/customer/delete", json=payload, headers=headers)
except httpx.HTTPStatusError as e:
    if e.response.status_code == 500 and "user_id is required" in e.response.text:
        raise ValueError("delete payload must include a non-empty user_ids list") from e
    raise

Prevention

When it happens

Trigger: POST /customer/delete with user_ids omitted, null, or an empty array [] in the JSON body.

Common situations: Templated scripts rendering an empty list when no candidates matched; cleanup loops that still issue the API call when the filtered set is empty; misconfigured JSON payloads using a different key name.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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