BerriAI/litellm · error · Exception
'user' param not passed in. 'enforce_user_param'={general_se
Error message
'user' param not passed in. 'enforce_user_param'={general_settings['enforce_user_param']} What it means
Raised by _enforce_user_param_check when general_settings.enforce_user_param is true in the proxy config and a POST to an OpenAI LLM route (chat/completions, embeddings, etc., excluding MCP routes) has no user field in the JSON body. Operators enable this flag to force per-end-user spend attribution on shared keys.
Source
Thrown at litellm/proxy/auth/auth_checks.py:524
project_object=project_object,
valid_token=valid_token,
proxy_logging_obj=proxy_logging_obj,
)
def _enforce_user_param_check(general_settings: dict, request: Request, request_body: dict, route: str) -> None:
if not general_settings.get("enforce_user_param", False):
return
http_method: Final = request.method if hasattr(request, "method") else None
is_post_method: Final = http_method and http_method.upper() == "POST"
is_openai_route: Final = RouteChecks.is_llm_api_route(route=route)
is_mcp_route: Final = route in LiteLLMRoutes.mcp_routes.value or RouteChecks.check_route_access(
route=route, allowed_routes=LiteLLMRoutes.mcp_routes.value
)
if is_post_method and is_openai_route and not is_mcp_route and "user" not in request_body:
raise Exception(f"'user' param not passed in. 'enforce_user_param'={general_settings['enforce_user_param']}")
def _reject_clientside_metadata_tags_check(general_settings: dict, request_body: dict, route: str) -> None:
if not general_settings.get("reject_clientside_metadata_tags", False):
return
if (
RouteChecks.is_llm_api_route(route=route)
and "metadata" in request_body
and isinstance(request_body["metadata"], dict)
and "tags" in request_body["metadata"]
):
raise ProxyException(
message=f"Client-side 'metadata.tags' not allowed in request. 'reject_clientside_metadata_tags'={general_settings['reject_clientside_metadata_tags']}. Tags can only be set via API key metadata.",
type=ProxyErrorTypes.bad_request_error,
param="metadata.tags",
code=status.HTTP_400_BAD_REQUEST,
)View on GitHub (pinned to 77b7c6c40c)
Solutions
- Add "user": "<end-user-or-customer-id>" to every completion/embedding request body
- If you control the proxy config and do not need forced attribution, set enforce_user_param: false
- Centralize the user field in a shared request-builder so no call site can omit it
Example fix
# before client.chat.completions.create(model="gpt-4o", messages=[...]) # after client.chat.completions.create(model="gpt-4o", messages=[...], user="user-123")
Defensive patterns
Strategy: validation
Validate before calling
def with_required_user(body: dict, end_user_id: str) -> dict:
if "user" not in body:
body["user"] = end_user_id
return body
payload = with_required_user({"model": "gpt-4o", "messages": messages}, "user-123") Try / catch
try:
resp = client.chat.completions.create(**payload)
except Exception as e:
if "enforce_user_param" in str(e):
raise ValueError("proxy requires 'user' on every completion call") from e
raise Prevention
- Wrap the OpenAI client so every completion/embedding call injects user automatically
- Document the enforced flag in onboarding for anyone using shared keys
- Add a CI check that greps request-building code for missing user fields when the flag is on
When it happens
Trigger: Config has general_settings.enforce_user_param: true, then a client POSTs /v1/chat/completions or /v1/embeddings whose body omits "user". MCP routes are exempted, but all standard OpenAI-format completion routes are covered.
Common situations: A platform turns on enforce_user_param to attribute spend to customers, and existing SDK integrations (openai client, LangChain) that never send user start failing; new client code paths forget the field.
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
- messages parameter is required
- Client-side 'metadata.tags' not allowed in request. 'reject_
- LLM Router not initialized. Ensure models added to proxy.
- DB not connected. This endpoint needs a database; set DATABA
- {custom_llm_provider.capitalize()}Exception - Use 'watsonx_t
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/9c4847c1f76a807d.
Report an issue: GitHub.