{"record":{"id":"7c1a1637cd79aa80","repo":"BerriAI/litellm","slug":"username-is-required-in-litellm-params-when-auth","errorCode":null,"errorMessage":"'username' is required in litellm_params when auth_mode='cp4d'","messagePattern":"'username' is required in litellm_params when auth_mode='cp4d'","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/a2a_protocol/providers/watsonx_orchestrate/handler.py","lineNumber":98,"sourceCode":"        if client is None:\n            client = WatsonxOrchestrateHandler._http_client(timeout=30.0)\n\n        if auth_mode == \"ibm_cloud\":\n            response = await client.post(\n                _IBM_CLOUD_IAM_URL,\n                data={\n                    \"grant_type\": \"urn:ibm:params:oauth:grant-type:apikey\",\n                    \"apikey\": api_key,\n                },\n                headers={\"Content-Type\": \"application/x-www-form-urlencoded\"},\n            )\n            response.raise_for_status()\n            payload = response.json()\n            token = str(payload[\"access_token\"])\n            ttl_s = int(payload.get(\"expires_in\", 3600))\n        else:\n            if not username:\n                raise ValueError(\"'username' is required in litellm_params when auth_mode='cp4d'\")\n            token_url: Final = f\"{cp4d_host.rstrip('/')}/icp4d-api/v1/authorize\"\n            response = await client.post(\n                token_url,\n                json={\"username\": username, \"api_key\": api_key},\n                headers={\"Content-Type\": \"application/json\"},\n            )\n            response.raise_for_status()\n            payload = response.json()\n            token = str(payload[\"token\"])\n            expiration: Final = payload.get(\"expiration\")\n            if expiration is None:\n                ttl_s = 3600\n            else:\n                ttl_s = WatsonxOrchestrateHandler._cp4d_token_ttl_seconds(expiration)\n\n        expires_at: Final = now + max(ttl_s - _TOKEN_CACHE_TTL_BUFFER_S, 0)\n        _token_cache[cache_key] = (token, expires_at)\n        for stale_key, (_, stale_expires_at) in list(_token_cache.items()):","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/a2a_protocol/providers/watsonx_orchestrate/handler.py#L80-L116","documentation":"Raised during watsonx Orchestrate token acquisition when auth_mode='cp4d' but no `username` is present in litellm_params. CP4D authorization posts username + api_key to /icp4d-api/v1/authorize; unlike the default API-key grant, a username is mandatory.","triggerScenarios":"litellm_params has auth_mode='cp4d' (or otherwise not the default apikey grant) and username is None when the handler fetches a token.","commonSituations":"Switching a deployment from Zen/API-key auth to CP4D user auth and forgetting username; assuming api_key alone is enough because it is for the default mode.","solutions":["Add `username` to litellm_params / the watsonx Orchestrate deployment config","If you intended pure API-key auth, remove auth_mode='cp4d' so the default grant-type:apikey flow is used"],"exampleFix":"# before\nlitellm_params={\"cp4d_host\": host, \"instance_id\": iid, \"wxo_agent_id\": aid, \"api_key\": key, \"auth_mode\": \"cp4d\"}\n# after\nlitellm_params={\"cp4d_host\": host, \"instance_id\": iid, \"wxo_agent_id\": aid, \"api_key\": key, \"auth_mode\": \"cp4d\", \"username\": \"user@corp.com\"}","handlingStrategy":"validation","validationCode":"lp = kwargs.get(\"litellm_params\", {})\nif lp.get(\"auth_mode\") == \"cp4d\" and not lp.get(\"username\"):\n    raise ValueError(\"cp4d auth requires username alongside api_key\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["When switching auth_mode to cp4d, add username to the deployment config in the same change","Document per auth_mode which credential fields are required"],"tags":["a2a","litellm","watsonx-orchestrate","authentication","cp4d","config"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}