BerriAI/litellm · error · WatsonXAIError
Error: Watsonx API base not set. Set WATSONX_API_BASE in env
Error message
Error: Watsonx API base not set. Set WATSONX_API_BASE in environment variables or pass in as parameter - 'api_base='.
What it means
Companion check to the api_key guard in the same credential step: after merging wx_credentials, api_base must be a non-None str. The URL is resolved from the api_base argument or wx_credentials['url']; if still missing, this WatsonXAIError (401) is raised. The env-chain lookup (WATSONX_API_BASE etc.) used elsewhere does not run on this branch, so the value must arrive via argument or the credentials dict.
Source
Thrown at litellm/llms/watsonx/common_utils.py:330
token: str | None = None
if wx_credentials is not None:
api_base = wx_credentials.get("url", api_base)
api_key = wx_credentials.get("apikey", wx_credentials.get("api_key", api_key))
token = wx_credentials.get(
"token",
wx_credentials.get(
"watsonx_token", None
), # follow format of {provider}_token, same as azure - e.g. 'azure_ad_token=..'
)
if api_key is None or not isinstance(api_key, str):
raise WatsonXAIError(
status_code=401,
message="Error: Watsonx API key not set. Set WATSONX_API_KEY in environment variables or pass in as parameter - 'api_key='.",
)
if api_base is None or not isinstance(api_base, str):
raise WatsonXAIError(
status_code=401,
message="Error: Watsonx API base not set. Set WATSONX_API_BASE in environment variables or pass in as parameter - 'api_base='.",
)
return WatsonXCredentials(api_key=api_key, api_base=api_base, token=cast(str | None, token))
def _prepare_payload(self, model: str, api_params: WatsonXAPIParams) -> dict:
payload: Final[dict] = {}
if model.startswith("deployment/"):
return {} # Deployment models do not support 'space_id' or 'project_id' in their payload
payload["model_id"] = model
if api_params["project_id"] is not None:
payload["project_id"] = api_params["project_id"]
else:
payload["space_id"] = api_params["space_id"]
return payload
View on GitHub (pinned to 77b7c6c40c)
Solutions
- Pass api_base explicitly to the call.
- Or include "url" in wx_credentials: wx_credentials={'url': 'https://us-south.ml.cloud.ibm.com', 'apikey': ...}.
- Also export WATSONX_API_BASE so other watsonx paths resolve it consistently.
- Validate the assembled config object before the request: url must be a non-empty string.
Example fix
# before
wx_credentials = {"apikey": os.environ["WATSONX_APIKEY"]} # no url
# ... -> WatsonXAIError: Watsonx API base not set...
# after
wx_credentials = {
"url": "https://us-south.ml.cloud.ibm.com",
"apikey": os.environ["WATSONX_APIKEY"],
} Defensive patterns
Strategy: validation
Validate before calling
def watsonx_url_ok(api_base: str | None, wx_credentials: dict | None) -> bool:
if isinstance(api_base, str) and api_base:
return True
if isinstance(wx_credentials, dict):
url = wx_credentials.get("url")
if isinstance(url, str) and url:
return True
return False
if not watsonx_url_ok(api_base, wx_credentials):
raise RuntimeError("WatsonX needs api_base or wx_credentials['url']") Type guard
const watsonxUrlOk = (apiBase?: string, wx?: Record<string, unknown>): boolean => (typeof apiBase === "string" && apiBase.length > 0) || (typeof wx?.url === "string" && (wx.url as string).length > 0);
Try / catch
from litellm.llms.watsonx.common_utils import WatsonXAIError
try:
resp = litellm.completion(model="watsonx/...", messages=msgs)
except WatsonXAIError as e:
if "Watsonx API base not set" in e.message:
raise RuntimeError("Pass api_base or wx_credentials={'url': ...}") from e
raise Prevention
- Always include 'url' in wx_credentials alongside 'apikey'.
- Also export WATSONX_API_BASE for the other watsonx code paths.
- Validate the whole credentials object (url + apikey) once at startup.
When it happens
Trigger: Passing wx_credentials with only 'apikey' and no 'url'; calling with api_base=None and no url in credentials; api_base accidentally set to a non-string (e.g. a URL object or None from a failed os.getenv chain).
Common situations: Config templating that leaves the url field blank in non-prod; splitting credentials across multiple dicts and dropping the url one; assuming WATSONX_API_BASE env is read here when only argument/credentials are checked.
Related errors
- Error: Watsonx URL not set. Set WATSONX_API_BASE in environm
- Error: Watsonx API key not set. Set WATSONX_API_KEY in envir
- Failed to retrieve file {file_id} from provider: {str(e)}
- API key is required for OpenAI image variations
- API base is required for OpenAI image variations
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/0580d014027ae647.
Report an issue: GitHub.