BerriAI/litellm · error · ValueError
'username' is required in litellm_params when auth_mode='cp4
Error message
'username' is required in litellm_params when auth_mode='cp4d'
What it means
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.
Source
Thrown at litellm/a2a_protocol/providers/watsonx_orchestrate/handler.py:98
if client is None:
client = WatsonxOrchestrateHandler._http_client(timeout=30.0)
if auth_mode == "ibm_cloud":
response = await client.post(
_IBM_CLOUD_IAM_URL,
data={
"grant_type": "urn:ibm:params:oauth:grant-type:apikey",
"apikey": api_key,
},
headers={"Content-Type": "application/x-www-form-urlencoded"},
)
response.raise_for_status()
payload = response.json()
token = str(payload["access_token"])
ttl_s = int(payload.get("expires_in", 3600))
else:
if not username:
raise ValueError("'username' is required in litellm_params when auth_mode='cp4d'")
token_url: Final = f"{cp4d_host.rstrip('/')}/icp4d-api/v1/authorize"
response = await client.post(
token_url,
json={"username": username, "api_key": api_key},
headers={"Content-Type": "application/json"},
)
response.raise_for_status()
payload = response.json()
token = str(payload["token"])
expiration: Final = payload.get("expiration")
if expiration is None:
ttl_s = 3600
else:
ttl_s = WatsonxOrchestrateHandler._cp4d_token_ttl_seconds(expiration)
expires_at: Final = now + max(ttl_s - _TOKEN_CACHE_TTL_BUFFER_S, 0)
_token_cache[cache_key] = (token, expires_at)
for stale_key, (_, stale_expires_at) in list(_token_cache.items()):View on GitHub (pinned to 6c2dcb801b)
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
Example fix
# before
litellm_params={"cp4d_host": host, "instance_id": iid, "wxo_agent_id": aid, "api_key": key, "auth_mode": "cp4d"}
# after
litellm_params={"cp4d_host": host, "instance_id": iid, "wxo_agent_id": aid, "api_key": key, "auth_mode": "cp4d", "username": "user@corp.com"} Defensive patterns
Strategy: validation
Validate before calling
lp = kwargs.get("litellm_params", {})
if lp.get("auth_mode") == "cp4d" and not lp.get("username"):
raise ValueError("cp4d auth requires username alongside api_key") Prevention
- 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
When it happens
Trigger: litellm_params has auth_mode='cp4d' (or otherwise not the default apikey grant) and username is None when the handler fetches a token.
Common situations: 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.
Related errors
- Either a2a_client or api_base is required for standard A2A f
- litellm_params is required for WatsonxOrchestrateA2AConfig (
- Error: {response.status_code} - {response.text}
- Missing Authorization header
- Invalid bearer token
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/7c1a1637cd79aa80.
Report an issue: GitHub.