{"record":{"id":"7d0d227f606f11f2","repo":"BerriAI/litellm","slug":"api-key-is-required-7d0d22","errorCode":null,"errorMessage":"API key is required","messagePattern":"API key is required","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/llms/watsonx/common_utils.py","lineNumber":46,"sourceCode":"def get_watsonx_iam_url():\n    return get_secret_str(\"WATSONX_IAM_URL\") or \"https://iam.cloud.ibm.com/identity/token\"\n\n\ndef generate_iam_token(api_key=None, **params) -> str:\n    result: str | None = iam_token_cache.get_cache(api_key)\n\n    if result is None:\n        headers: Final = {}\n        headers[\"Content-Type\"] = \"application/x-www-form-urlencoded\"\n        if api_key is None:\n            api_key = (\n                get_secret_str(\"WX_API_KEY\")\n                or get_secret_str(\"WATSONX_API_KEY\")\n                or get_secret_str(\"WATSONX_APIKEY\")\n                or get_secret_str(\"WATSONX_ZENAPIKEY\")\n            )\n        if api_key is None:\n            raise ValueError(\"API key is required\")\n        headers[\"Accept\"] = \"application/json\"\n        data: Final = {\n            \"grant_type\": \"urn:ibm:params:oauth:grant-type:apikey\",\n            \"apikey\": api_key,\n        }\n        iam_token_url: Final = get_watsonx_iam_url()\n        verbose_logger.debug(\n            \"calling ibm `/identity/token` to retrieve IAM token.\\nURL=%s\\nheaders=%s\\ndata=%s\",\n            iam_token_url,\n            headers,\n            data,\n        )\n        response: Final = litellm.module_level_client.post(url=iam_token_url, data=data, headers=headers)\n        response.raise_for_status()\n        json_data: Final = response.json()\n\n        result = json_data[\"access_token\"]\n        iam_token_cache.set_cache(","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/llms/watsonx/common_utils.py#L28-L64","documentation":"generate_iam_token exchanges your WatsonX API key for an IBM IAM access token by POSTing to https://iam.cloud.ibm.com/identity/token. The key is taken from the api_key argument or the env chain WX_API_KEY / WATSONX_API_KEY / WATSONX_APIKEY / WATSONX_ZENAPIKEY; if all are empty, this bare ValueError('API key is required') is raised before the IAM call. It fires when you authenticate with api_key (as opposed to passing a ready-made token).","triggerScenarios":"litellm.completion(model=\"watsonx/...\", messages=[...]) without api_key/token and with none of the four env vars set; using WATSONX_API_KEY_TYPO-style names; Zen-style deployments (WATSONX_ZENAPIKEY) missing in local dev.","commonSituations":"Local runs where keys live only in the deployed environment; notebooks that never call load_dotenv; migrations from IBM Watson Studio env var conventions to litellm; service containers with scrubbed env.","solutions":["export WATSONX_APIKEY=<key> (or WX_API_KEY / WATSONX_API_KEY / WATSONX_ZENAPIKEY).","Or pass api_key directly to the call / proxy model config.","If you already have an IAM token, pass token=... (or watsonx_token) instead - that path skips generate_iam_token.","Add a preflight check that at least one of the four env vars is non-empty."],"exampleFix":"# before\nresp = litellm.completion(model=\"watsonx/mistralai/mistral-large\", messages=[{\"role\": \"user\", \"content\": \"hi\"}])\n# -> ValueError: API key is required (from IAM token exchange)\n\n# after\nimport os\nos.environ[\"WATSONX_APIKEY\"] = \"<your-ibm-apikey>\"\nos.environ[\"WATSONX_PROJECT_ID\"] = \"<your-project-id>\"\nresp = litellm.completion(model=\"watsonx/mistralai/mistral-large\", messages=[{\"role\": \"user\", \"content\": \"hi\"}])","handlingStrategy":"validation","validationCode":"import os\n\nWX_KEY = (\n    os.getenv(\"WX_API_KEY\")\n    or os.getenv(\"WATSONX_API_KEY\")\n    or os.getenv(\"WATSONX_APIKEY\")\n    or os.getenv(\"WATSONX_ZENAPIKEY\")\n)\nif not WX_KEY and not os.getenv(\"WATSONX_TOKEN\"):\n    raise RuntimeError(\"WatsonX needs an API key (WX_API_KEY, WATSONX_APIKEY, ...) or a token\")\nresp = litellm.completion(model=\"watsonx/...\", messages=msgs)","typeGuard":"const hasWatsonxAuth = (env: Record<string, string | undefined>): boolean =>\n  Boolean(\n    env.WX_API_KEY ?? env.WATSONX_API_KEY ?? env.WATSONX_APIKEY ??\n    env.WATSONX_ZENAPIKEY ?? env.WATSONX_TOKEN\n  );","tryCatchPattern":"try:\n    resp = litellm.completion(model=\"watsonx/...\", messages=msgs)\nexcept ValueError as e:\n    if str(e) == \"API key is required\":\n        raise RuntimeError(\"Set WATSONX_APIKEY (or pass token=) for WatsonX IAM auth\") from e\n    raise","preventionTips":["Set WATSONX_APIKEY in every environment; the IAM token exchange runs on first call.","If you already hold an IAM token, pass token=... to skip the exchange entirely.","Assert the env var in deployment healthchecks so failures surface before traffic."],"tags":["watsonx","iam","api-key","authentication","environment-variable","litellm"],"backgroundTag":"missing-api-key","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}