BerriAI/litellm · error · GenAIHubOrchestrationError

{err.args[0]}

Error message

{err.args[0]}

What it means

Before the first SAP call, run_env_setup resolves credentials via get_token_creator; any ValueError from that chain (no credentials found in any source, missing auth_url/client_id/base_url, or an ambiguous auth mode - not exactly one of client_secret, cert pair, or cert files) is wrapped as GenAIHubOrchestrationError 400. The message names the exact credential problem.

Source

Thrown at litellm/llms/sap/chat/transformation.py:142

        temperature: int | None = None,
        top_p: int | None = None,
        response_format: dict | None = None,
        tools: list | None = None,
        tool_choice: str | dict | None = None,
    ) -> None:
        locals_: Final = locals().copy()
        for key, value in locals_.items():
            if key != "self" and value is not None:
                setattr(self.__class__, key, value)
        self.token_creator = None
        self._base_url = None
        self._resource_group = None

    def run_env_setup(self, service_key: str | None = None) -> None:
        try:
            self.token_creator, self._base_url, self._resource_group = get_token_creator(service_key)
        except ValueError as err:
            raise GenAIHubOrchestrationError(status_code=400, message=err.args[0])

    @property
    def headers(self) -> dict[str, str]:
        if self.token_creator is None:
            self.run_env_setup()
        access_token = self.token_creator()  # pyright: ignore[reportOptionalCall]  # run_env_setup set it or raised
        return {
            "Authorization": access_token,
            "AI-Resource-Group": self.resource_group,
            "Content-Type": "application/json",
            "AI-Client-Type": "LiteLLM",
        }

    @property
    def base_url(self) -> str:
        if self._base_url is None:
            self.run_env_setup()
        return self._base_url

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Set the full secret-auth set: AICORE_CLIENT_ID, AICORE_CLIENT_SECRET, AICORE_AUTH_URL, AICORE_BASE_URL (and optionally AICORE_RESOURCE_GROUP).
  2. Or pass the whole service key once: os.environ['AICORE_SERVICE_KEY'] = json.dumps(service_key_dict) or litellm.sap_service_key = service_key.
  3. If using certificate auth, provide exactly one of cert_str+key_str or cert_file_path+key_file_path - and remove client_secret.
  4. Check the wrapped message: 'No credentials found in any source' vs 'credentials are incomplete' tells you whether nothing or only partial config was found.

Example fix

# before - incomplete env
os.environ['AICORE_CLIENT_ID'] = '...'
# after - complete secret auth
os.environ['AICORE_CLIENT_ID'] = '...'
os.environ['AICORE_CLIENT_SECRET'] = '...'
os.environ['AICORE_AUTH_URL'] = 'https://<tenant>.authentication.sap.hana.ondemand.com/oauth/token'
os.environ['AICORE_BASE_URL'] = 'https://api.ai.prod.eu-central-1.aws.ml.hana.ondemand.com/v2'
Defensive patterns

Strategy: validation

Validate before calling

import os

REQUIRED_ENV = ['AICORE_CLIENT_ID', 'AICORE_CLIENT_SECRET', 'AICORE_AUTH_URL', 'AICORE_BASE_URL']
missing = [k for k in REQUIRED_ENV if not os.environ.get(k)]
if missing:
    raise RuntimeError(f'SAP credentials incomplete, missing: {missing}')
resp = litellm.completion(model='sap/...', messages=msgs)

Try / catch

from litellm.llms.sap.chat.handler import GenAIHubOrchestrationError

try:
    resp = litellm.completion(model='sap/gpt-4o', messages=msgs)
except GenAIHubOrchestrationError as e:
    if e.status_code == 400:
        raise RuntimeError(f'SAP credential setup failed: {e.message}') from e
    raise

Prevention

When it happens

Trigger: Calling litellm.completion(model='sap/...') with no AICORE_* environment variables, no AICORE_SERVICE_KEY, no ~/.aicore/config.json, and no service_key passed; or credentials that are incomplete (e.g. client_id and secret set but no AICORE_AUTH_URL/AICORE_BASE_URL); or multiple auth methods supplied at once (secret plus certificate).

Common situations: New environments where only some AICORE_* vars are exported; service keys pasted with missing fields; switching between secret-based and mTLS certificate auth and leaving both partially configured; k8s secrets mounted for a different profile than AICORE_PROFILE selects.

Related errors


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/afdca9867183538f. Report an issue: GitHub.