BerriAI/litellm · error · RuntimeError

Failed to get Azure AD token: {e}

Error message

Failed to get Azure AD token: {e}

What it means

The azure_ad_token_provider callable raised an exception (anything other than the TypeError from 1025). LiteLLM wraps it in RuntimeError('Failed to get Azure AD token: {e}') chained to the original. The root cause is in the provider itself — credential errors, network failure to IMDS, missing env, etc.

Source

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

            azure_ad_token_provider = BaseAzureLLM._try_get_default_azure_credential_provider(
                scope=scope,
            )

    # Execute the token provider to get the token if available
    if azure_ad_token_provider and callable(azure_ad_token_provider):
        try:
            token: Final = azure_ad_token_provider()
            if not isinstance(token, str):
                verbose_logger.error("Azure AD token provider returned non-string value: %s", type(token))
                raise TypeError(f"Azure AD token must be a string, got {type(token)}")
            else:
                azure_ad_token = token
        except TypeError:
            # Re-raise TypeError directly
            raise
        except Exception as e:
            verbose_logger.error("Error calling Azure AD token provider: %s", e)
            raise RuntimeError(f"Failed to get Azure AD token: {e}") from e

    return azure_ad_token


class BaseAzureLLM(BaseOpenAILLM):
    @staticmethod
    def _try_get_default_azure_credential_provider(
        scope: str,
    ) -> Callable[[], str] | None:
        """
        Try to get DefaultAzureCredential provider

        Args:
            scope: Azure scope for the token

        Returns:
            Token provider callable if DefaultAzureCredential is enabled and available, None otherwise
        """

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Read the chained cause (raise ... from e preserves it; log e.__cause__) — it names the failing credential.
  2. In containers, ensure exactly one credential source is available: managed identity enabled, or AZURE_CLIENT_ID/AZURE_TENANT_ID/client secret env vars, or a mounted CLI token cache.
  3. Allow IMDS traffic (169.254.169.254) and set AZURE_CLIENT_ID for user-assigned managed identity.
  4. Catch the provider error yourself and retry once with a fresh credential instance to handle transient IMDS 410/503s.

Example fix

# before
litellm.completion(model="azure/dep", messages=msgs, azure_ad_token_provider=lambda: DefaultAzureCredential().get_token(S).token)

# after (clear failure + actionable message)
def provider():
    try:
        return DefaultAzureCredential().get_token(S).token
    except Exception as e:
        raise RuntimeError(f"credential chain failed; check managed identity/env: {e}") from e
litellm.completion(model="azure/dep", messages=msgs, azure_ad_token_provider=provider)
Defensive patterns

Strategy: try-catch

Validate before calling

def probe_credential() -> None:
    from azure.identity import DefaultAzureCredential
    DefaultAzureCredential().get_token("https://cognitiveservices.azure.com/.default")  # fails fast, clear error

Try / catch

try:
    resp = litellm.completion(..., azure_ad_token_provider=provider)
except RuntimeError as e:
    cause = e.__cause__
    log.error("token provider failed: %s", cause)
    if "CredentialUnavailable" in type(cause).__name__:
        raise ConfigError("No Azure credential source in this environment") from e
    raise

Prevention

When it happens

Trigger: DefaultAzureCredential raising ClientAuthenticationError (no env vars, no managed identity, no CLI login in a container); IMDS endpoint unreachable (169.254.169.254 blocked); azure-identity exceptions like CredentialUnavailableError propagating out of the provider.

Common situations: Local code using DefaultAzureCredential works (CLI login) but the Docker container has none of the credential sources; IMDS calls blocked by network policy; expired az login refresh tokens; workloads where SharedTokenCacheCredential throws.

Related errors


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