{"record":{"id":"9c4847c1f76a807d","repo":"BerriAI/litellm","slug":"user-param-not-passed-in-enforce-user-param","errorCode":null,"errorMessage":"'user' param not passed in. 'enforce_user_param'={general_settings['enforce_user_param']}","messagePattern":"'user' param not passed in\\. 'enforce_user_param'=(.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"litellm/proxy/auth/auth_checks.py","lineNumber":524,"sourceCode":"            project_object=project_object,\n            valid_token=valid_token,\n            proxy_logging_obj=proxy_logging_obj,\n        )\n\n\ndef _enforce_user_param_check(general_settings: dict, request: Request, request_body: dict, route: str) -> None:\n    if not general_settings.get(\"enforce_user_param\", False):\n        return\n\n    http_method: Final = request.method if hasattr(request, \"method\") else None\n    is_post_method: Final = http_method and http_method.upper() == \"POST\"\n    is_openai_route: Final = RouteChecks.is_llm_api_route(route=route)\n    is_mcp_route: Final = route in LiteLLMRoutes.mcp_routes.value or RouteChecks.check_route_access(\n        route=route, allowed_routes=LiteLLMRoutes.mcp_routes.value\n    )\n\n    if is_post_method and is_openai_route and not is_mcp_route and \"user\" not in request_body:\n        raise Exception(f\"'user' param not passed in. 'enforce_user_param'={general_settings['enforce_user_param']}\")\n\n\ndef _reject_clientside_metadata_tags_check(general_settings: dict, request_body: dict, route: str) -> None:\n    if not general_settings.get(\"reject_clientside_metadata_tags\", False):\n        return\n\n    if (\n        RouteChecks.is_llm_api_route(route=route)\n        and \"metadata\" in request_body\n        and isinstance(request_body[\"metadata\"], dict)\n        and \"tags\" in request_body[\"metadata\"]\n    ):\n        raise ProxyException(\n            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.\",\n            type=ProxyErrorTypes.bad_request_error,\n            param=\"metadata.tags\",\n            code=status.HTTP_400_BAD_REQUEST,\n        )","sourceCodeStart":506,"sourceCodeEnd":542,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/auth/auth_checks.py#L506-L542","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\nclient.chat.completions.create(model=\"gpt-4o\", messages=[...])\n\n# after\nclient.chat.completions.create(model=\"gpt-4o\", messages=[...], user=\"user-123\")","handlingStrategy":"validation","validationCode":"def with_required_user(body: dict, end_user_id: str) -> dict:\n    if \"user\" not in body:\n        body[\"user\"] = end_user_id\n    return body\n\npayload = with_required_user({\"model\": \"gpt-4o\", \"messages\": messages}, \"user-123\")","typeGuard":null,"tryCatchPattern":"try:\n    resp = client.chat.completions.create(**payload)\nexcept Exception as e:\n    if \"enforce_user_param\" in str(e):\n        raise ValueError(\"proxy requires 'user' on every completion call\") from e\n    raise","preventionTips":["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"],"tags":["enforce-user-param","spend-attribution","general-settings","bad-request","litellm-proxy"],"backgroundTag":"missing-required-parameter","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}