BerriAI/litellm · error · ValueError

Either user_id or user_email must be provided

Error message

Either user_id or user_email must be provided

What it means

UpdateUserRequest has optional user_id and user_email, but _update_single_user_helper requires at least one to identify the target; otherwise it raises ValueError 'Either user_id or user_email must be provided'. Because it is a ValueError (not HTTPException), /user/update converts it into a ProxyException 'Authentication Error, Either user_id or user_email must be provided' with code 400 - the auth prefix is cosmetic.

Source

Thrown at litellm/proxy/management_endpoints/internal_user_endpoints.py:1358

async def _update_single_user_helper(
    user_request: UpdateUserRequest,
    user_api_key_dict: UserAPIKeyAuth,
    litellm_changed_by: str | None = None,
) -> dict[str, Any]:
    """
    Helper function to update a single user.
    Used by both user_update and bulk_user_update endpoints.

    Returns the updated user data or raises an exception on failure.
    """
    from litellm.proxy.proxy_server import litellm_proxy_admin_name, prisma_client

    if prisma_client is None:
        raise Exception("Not connected to DB!")

    if not user_request.user_id and not user_request.user_email:
        raise ValueError("Either user_id or user_email must be provided")

    _check_permissions_caller_permission(
        data=user_request,
        user_api_key_dict=user_api_key_dict,
    )

    data_json: Final[dict] = user_request.model_dump(exclude_unset=True)
    non_default_values = _update_internal_user_params(data_json=data_json, data=user_request)
    _hash_password_in_dict(non_default_values)

    existing_user_row: BaseModel | None = None
    if user_request.user_id:
        existing_user_row = await _user_table(prisma_client).find_first(where={"user_id": user_request.user_id})
    elif user_request.user_email:
        existing_user_row = await _user_table(prisma_client).find_first(where={"user_email": user_request.user_email})

    _check_user_update_authz(user_request, user_api_key_dict, existing_user_row)

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Include user_id (or user_email) of the target user in the body
  2. For self-update, still pass your own user_id explicitly - there is no implicit self-targeting
  3. Validate the payload client-side before sending the request

Example fix

# before
POST /user/update {"user_alias": "Krrish"}   # 400 Authentication Error, Either user_id or user_email must be provided

# after
POST /user/update {"user_id": "krrish7@berri.ai", "user_alias": "Krrish"}  # 200
Defensive patterns

Strategy: validation

Validate before calling

def validate_update_payload(payload: dict) -> dict:
    if not payload.get("user_id") and not payload.get("user_email"):
        raise ValueError("UpdateUserRequest needs user_id or user_email")
    return payload

Type guard

interface UpdateUserRequest { user_id?: string; user_email?: string; [k: string]: unknown }
function hasUserIdentifiers(p: UpdateUserRequest): boolean {
  return (typeof p.user_id === "string" && p.user_id.length > 0)
      || (typeof p.user_email === "string" && p.user_email.length > 0);
}

Try / catch

except requests.HTTPError as e:
    body = e.response.text if e.response is not None else ""
    if e.response is not None and e.response.status_code == 400 and "user_id or user_email" in body:
        raise ValueError("payload must include user_id or user_email") from e
    raise

Prevention

When it happens

Trigger: POST /user/update with a body that contains neither user_id nor user_email - e.g. only user_alias or max_budget; dynamically built payloads where both identifiers were skipped.

Common situations: Client code assuming /user/update with no id targets the caller (it does not); forms that make both identifier fields optional; partial payloads after refactors.

Understand the failure class

Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.

Related errors


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