{"record":{"id":"5dbe2bc769b2acdb","repo":"BerriAI/litellm","slug":"api-key-is-required-in-litellm-params-for-wxo-ag","errorCode":null,"errorMessage":"'api_key' is required in litellm_params for WXO agents","messagePattern":"'api_key' is required in litellm_params for WXO agents","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/a2a_protocol/providers/watsonx_orchestrate/handler.py","lineNumber":203,"sourceCode":"            if chunk_text:\n                accumulated_text += chunk_text\n        return accumulated_text\n\n    @staticmethod\n    def _extract_litellm_params(litellm_params: dict[str, Any]) -> WXORequestParams:\n        cp4d_host: Final = litellm_params.get(\"cp4d_host\") or \"\"\n        instance_id: Final = litellm_params.get(\"instance_id\") or \"\"\n        wxo_agent_id: Final = litellm_params.get(\"wxo_agent_id\") or \"\"\n        api_key: Final = litellm_params.get(\"api_key\") or \"\"\n\n        if not cp4d_host:\n            raise ValueError(\"'cp4d_host' is required in litellm_params for WXO agents\")\n        if not instance_id:\n            raise ValueError(\"'instance_id' is required in litellm_params for WXO agents\")\n        if not wxo_agent_id:\n            raise ValueError(\"'wxo_agent_id' is required in litellm_params for WXO agents\")\n        if not api_key:\n            raise ValueError(\"'api_key' is required in litellm_params for WXO agents\")\n\n        return WXORequestParams(\n            cp4d_host=cp4d_host,\n            instance_id=instance_id,\n            wxo_agent_id=wxo_agent_id,\n            api_key=api_key,\n            username=litellm_params.get(\"username\") or None,\n            auth_mode=litellm_params.get(\"auth_mode\") or \"cp4d\",\n            thread_id=litellm_params.get(\"thread_id\") or None,\n        )\n\n    @staticmethod\n    async def handle_non_streaming(\n        request_id: str,\n        params: dict[str, Any],\n        litellm_params: dict[str, Any],\n    ) -> dict[str, Any]:\n        wxo: Final = WatsonxOrchestrateHandler._extract_litellm_params(litellm_params)","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/a2a_protocol/providers/watsonx_orchestrate/handler.py#L185-L221","documentation":"Configuration validation error from the WXO handler: 'api_key' is missing or empty in litellm_params. The api_key is the CP4D/WXO credential used for authentication, so the handler refuses to proceed without it rather than sending an unauthenticated request that would 401.","triggerScenarios":"WXO model config omitting 'api_key' or with an empty value. Runs last among the four ordered checks, so cp4d_host, instance_id, and wxo_agent_id must already be present. For SaaS-style auth_mode ('iam'), this key is still required by this validation.","commonSituations":"Expecting LiteLLM to pull the key from WATSONX_APIKEY env var automatically (it does not for this path — it must be in litellm_params); expired or rotated CP4D API key pasted as empty; secrets manager reference not resolved.","solutions":["Add 'api_key' to litellm_params (in the proxy, use os.environ/WATSONX_APIKEY-style indirection so the secret is not hardcoded).","If auth_mode is 'iam', ensure 'username' is also set and the api_key is the IAM key.","Restart the LiteLLM proxy after config changes so params are re-read."],"exampleFix":"# before\nlitellm_params:\n  model: watsonx_orchestrate/agent\n  cp4d_host: https://cpd.example.com:443\n  instance_id: 1f2a3b4c-...\n  wxo_agent_id: my-agent-id\n\n# after\nlitellm_params:\n  model: watsonx_orchestrate/agent\n  cp4d_host: https://cpd.example.com:443\n  instance_id: 1f2a3b4c-...\n  wxo_agent_id: my-agent-id\n  api_key: os.environ/WATSONX_APIKEY","handlingStrategy":"validation","validationCode":"def validate_wxo_config(litellm_params: dict) -> None:\n    missing = [k for k in (\"cp4d_host\", \"instance_id\", \"wxo_agent_id\", \"api_key\") if not litellm_params.get(k)]\n    if missing:\n        raise ConfigError(f\"WXO config missing: {missing}\")","typeGuard":"def has_valid_wxo_config(p: dict) -> bool:\n    return all(isinstance(p.get(k), str) and p[k].strip() for k in (\"cp4d_host\", \"instance_id\", \"wxo_agent_id\", \"api_key\"))","tryCatchPattern":null,"preventionTips":["Reference the key via env indirection (os.environ/WATSONX_APIKEY) rather than hardcoding.","Rotate CP4D API keys on a schedule and update the env var, not the config file.","Add a startup smoke test that makes one cheap WXO call to validate all four params end to end."],"tags":["watsonx-orchestrate","configuration","validation","authentication"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}