BerriAI/litellm · error · AzureOpenAIError

{req_token.text}

Error message

{req_token.text}

What it means

LiteLLM posts the client-credentials request (client_assertion = your OIDC token) to {AZURE_AUTHORITY_HOST}/{tenant}/oauth2/v2.0/token. If Azure AD replies with any non-200 status, LiteLLM re-raises AzureOpenAIError with the same status code and the raw response body (message=req_token.text). The body is Azure AD's own error JSON, e.g. invalid_client, invalid_scope, or AADSTS70021.

Source

Thrown at litellm/llms/azure/common_utils.py:235

    azure_ad_token_access_token = azure_ad_cache.get_cache(azure_ad_token_cache_key)
    if azure_ad_token_access_token is not None:
        return azure_ad_token_access_token

    client: Final = litellm.module_level_client

    req_token: Final = client.post(
        f"{azure_authority_host}/{azure_tenant_id}/oauth2/v2.0/token",
        data={
            "client_id": azure_client_id,
            "grant_type": "client_credentials",
            "scope": scope,
            "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
            "client_assertion": oidc_token,
        },
    )

    if req_token.status_code != 200:
        raise AzureOpenAIError(
            status_code=req_token.status_code,
            message=req_token.text,
        )

    azure_ad_token_json: Final[_AzureAdTokenJson] = req_token.json()
    azure_ad_token_access_token = azure_ad_token_json.get("access_token", None)
    azure_ad_token_expires_in: Final = azure_ad_token_json.get("expires_in", None)

    if azure_ad_token_access_token is None:
        raise AzureOpenAIError(status_code=422, message="Azure AD Token access_token not returned")

    if azure_ad_token_expires_in is None:
        raise AzureOpenAIError(status_code=422, message="Azure AD Token expires_in not returned")

    azure_ad_cache.set_cache(
        key=azure_ad_token_cache_key,
        value=azure_ad_token_access_token,
        ttl=azure_ad_token_expires_in,

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Read the AADSTS code in the message body — it names the exact cause (e.g. AADSTS70021: no federated identity credentials found for the service account).
  2. For AADSTS7000215/700213: fetch a fresh OIDC token immediately before the LiteLLM call; tokens are typically valid ~5-90 min.
  3. Verify AZURE_TENANT_ID matches the directory the app registration/federated identity lives in.
  4. For sovereign clouds set AZURE_AUTHORITY_HOST appropriately (e.g. https://login.microsoftonline.us) and keep scope under that cloud's resource.
  5. Confirm a federated identity credential exists linking your OIDC issuer/subject to the app registration (AZURE_CLIENT_ID).

Example fix

# before
os.environ["AZURE_AUTHORITY_HOST"] = "https://login.microsoftonline.com"  # default, wrong cloud

# after (Azure US Government)
os.environ["AZURE_AUTHORITY_HOST"] = "https://login.microsoftonline.us"
Defensive patterns

Strategy: retry

Try / catch

try:
    resp = litellm.completion(..., azure_ad_token=oidc)
except AzureOpenAIError as e:
    body = str(e)
    if "AADSTS7000215" in body or "AADSTS700213" in body:  # expired/invalid assertion
        oidc = fetch_fresh_oidc()
        resp = litellm.completion(..., azure_ad_token=oidc)
    elif e.status_code in (429, 500, 503):
        backoff_and_retry()
    else:
        raise

Prevention

When it happens

Trigger: Expired or malformed OIDC assertion (AADSTS7000215 invalid_client); wrong tenant ID (AADSTS70001 application not found); scope not consented (e.g. requesting a scope other than https://cognitiveservices.azure.com/.default without permission); custom AZURE_AUTHORITY_HOST that is wrong or unreachable via proxy returns 404/403.

Common situations: Federated workload identity where the pod's service-account token TTL expired between fetch and use; copying a tenant ID from a different directory; sovereign-cloud deployments (AzureUSGovernment/AzureChina) that still point at login.microsoftonline.com; expired client secret when client_secret flow is mistakenly used.

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/2e50c69dd0c5663d. Report an issue: GitHub.