{"record":{"id":"a52696d19c5a073d","repo":"BerriAI/litellm","slug":"openmeter-user-is-required","errorCode":null,"errorMessage":"OpenMeter: user is required","messagePattern":"OpenMeter: user is required","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"litellm/integrations/openmeter.py","lineNumber":84,"sourceCode":"        # OPENMETER_TRUST_REQUEST_USER (default \"true\"): when set to \"false\",\n        # the request-supplied `user` field is ignored and the subject is\n        # resolved solely from the key-bound user_api_key_user_id. Proxies\n        # serving multi-tenant traffic enable this to prevent clients from\n        # forging attribution by setting `user` in the request body.\n        trust_request_user: Final = os.getenv(\"OPENMETER_TRUST_REQUEST_USER\", \"true\").lower() != \"false\"\n        user_param = kwargs.get(\"user\", None) if trust_request_user else None\n\n        # If no user provided directly, try to get it from token user_id\n        if user_param is None:\n            # Check if user_id is available from the API key metadata\n            litellm_params: Final = kwargs.get(\"litellm_params\", {})\n            metadata: Final = litellm_params.get(\"metadata\", {})\n            user_api_key_user_id: Final = metadata.get(\"user_api_key_user_id\", None)\n\n            if user_api_key_user_id is not None:\n                user_param = user_api_key_user_id\n            else:\n                raise Exception(\"OpenMeter: user is required\")\n\n        # Ensure subject is always a string for OpenMeter API\n        subject: Final = str(user_param)\n\n        return {\n            \"specversion\": \"1.0\",\n            \"type\": os.getenv(\"OPENMETER_EVENT_TYPE\", \"litellm_tokens\"),\n            \"id\": call_id,\n            \"time\": dt,\n            \"subject\": subject,\n            \"source\": \"litellm-proxy\",\n            \"data\": {\"model\": model, \"cost\": cost, **usage},\n        }\n\n    def log_success_event(self, kwargs, response_obj, start_time, end_time):\n        _url = os.getenv(\"OPENMETER_API_ENDPOINT\", \"https://openmeter.cloud\")\n        if _url.endswith(\"/\"):\n            _url += \"api/v1/events\"","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/integrations/openmeter.py#L66-L102","documentation":"OpenMeter events require a subject (end user) for metering. _common_logic tries kwargs['user'] (only when trust_request_user is enabled) and then the virtual-key metadata user_api_key_user_id; if neither exists it raises. OpenMeter's billing/metering model is per-subject, so an anonymous event is not representable.","triggerScenarios":"Calling litellm.completion without user= while trust_request_user is disabled or unset; proxy requests where the virtual key has no user_id attached (user_api_key_user_id absent from metadata); programmatic API-key calls with no user context.","commonSituations":"Teams enabling OpenMeter mid-project before tagging requests with users; proxy keys created without an owner user_id; clients that never send a user field.","solutions":["Pass user='<user-id>' on litellm.completion / proxy requests so kwargs carries it","In the proxy, attach a user_id to the virtual key so metadata.user_api_key_user_id is populated (create or update the key with a user_id)","Enable the setting that trusts the request user if your security model allows it, so kwargs['user'] is used directly","If subject attribution is impossible for some traffic, route those calls to a callback set without openmeter"],"exampleFix":"# before\nresponse = litellm.completion(model=\"gpt-4o\", messages=[...])\n# during openmeter logging: Exception: OpenMeter: user is required\n\n# after\nresponse = litellm.completion(\n    model=\"gpt-4o\",\n    messages=[...],\n    user=\"user-123\",  # becomes the OpenMeter event subject\n)","handlingStrategy":"validation","validationCode":"def openmeter_subject_available(kwargs: dict, trust_user: bool) -> bool:\n    if trust_user and kwargs.get(\"user\"):\n        return True\n    metadata = kwargs.get(\"litellm_params\", {}).get(\"metadata\", {})\n    return metadata.get(\"user_api_key_user_id\") is not None","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Require user= in your internal completion wrapper before callbacks run","Attach user_id to every proxy virtual key at creation time"],"tags":["python","openmeter","user-attribution","callback","proxy"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}