BerriAI/litellm · error · ValueError

api_key (Azure AD token) is required for Azure Foundry Agent

Error message

api_key (Azure AD token) is required for Azure Foundry Agents. Either pass api_key directly, or set AZURE_TENANT_ID, AZURE_CLIENT_ID, and AZURE_CLIENT_SECRET environment variables for Service Principal auth. Manual token: az account get-access-token --resource 'https://ai.azure.com'

What it means

Azure Foundry Agents authenticate with an Azure AD token for scope https://ai.azure.com/.default. LiteLLM first uses any passed api_key; otherwise it attempts get_azure_ad_token (service principal from AZURE_TENANT_ID/AZURE_CLIENT_ID/AZURE_CLIENT_SECRET, or DefaultAzureCredential). Only if both yield nothing does it raise this ValueError listing every accepted auth route.

Source

Thrown at litellm/llms/azure_ai/agents/transformation.py:350

          - AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET (Service Principal)

        See: https://learn.microsoft.com/en-us/azure/ai-foundry/agents/quickstart
        """
        from litellm.llms.azure.common_utils import get_azure_ad_token
        from litellm.llms.azure_ai.agents.handler import azure_ai_agents_handler
        from litellm.types.router import GenericLiteLLMParams

        # If no api_key is provided, try to get Azure AD token
        if api_key is None:
            # Try to get Azure AD token using the existing Azure auth mechanisms
            # This uses the scope for Azure AI (ai.azure.com) instead of cognitive services
            # Create a GenericLiteLLMParams with the scope override for Azure Foundry Agents
            azure_auth_params: Final = dict(litellm_params) if litellm_params else {}
            azure_auth_params["azure_scope"] = "https://ai.azure.com/.default"
            api_key = get_azure_ad_token(GenericLiteLLMParams(**azure_auth_params))

        if api_key is None:
            raise ValueError(
                "api_key (Azure AD token) is required for Azure Foundry Agents. "
                "Either pass api_key directly, or set AZURE_TENANT_ID, AZURE_CLIENT_ID, "
                "and AZURE_CLIENT_SECRET environment variables for Service Principal auth. "
                "Manual token: az account get-access-token --resource 'https://ai.azure.com'"
            )
        if acompletion:
            if stream:
                # Native async streaming via SSE - return the async generator directly
                return azure_ai_agents_handler.acompletion_stream(
                    model=model,
                    messages=messages,
                    api_base=api_base,
                    api_key=api_key,
                    logging_obj=logging_obj,
                    optional_params=optional_params,
                    litellm_params=litellm_params,
                    timeout=timeout,
                    headers=headers,

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. For quick testing, mint a token manually and pass it: az account get-access-token --resource 'https://ai.azure.com' then api_key=<token>.
  2. For production, set AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET for a service principal granted access to the Foundry project.
  3. If on an Azure VM/App Service, enable a managed identity and grant it the project role so DefaultAzureCredential works.
  4. Verify env vars are visible to the litellm process (print names, never values) — a missing var silently triggers this path.

Example fix

# before
litellm.completion(model='azure_ai_agents/agent', messages=m, api_base=base)  # no auth anywhere

# after (service principal)
import os
os.environ['AZURE_TENANT_ID'] = '...'
os.environ['AZURE_CLIENT_ID'] = '...'
os.environ['AZURE_CLIENT_SECRET'] = '...'
litellm.completion(model='azure_ai_agents/agent', messages=m, api_base=base)

# after (manual token, short-lived)
import subprocess
tok = subprocess.check_output(
    ['az','account','get-access-token','--resource','https://ai.azure.com','--query','accessToken','-o','tsv']
).decode().strip()
litellm.completion(model='azure_ai_agents/agent', messages=m, api_base=base, api_key=tok)
Defensive patterns

Strategy: validation

Validate before calling

import os

def foundry_auth_ok(api_key: str | None) -> bool:
    if api_key:
        return True
    return all(os.getenv(v) for v in ('AZURE_TENANT_ID', 'AZURE_CLIENT_ID', 'AZURE_CLIENT_SECRET'))

Try / catch

try:
    litellm.completion(model='azure_ai_agents/agent', api_base=base, api_key=token)
except ValueError as e:
    if 'api_key (Azure AD token) is required' in str(e):
        raise ConfigurationError('Configure service principal env vars or pass a token') from e
    raise

Prevention

When it happens

Trigger: No api_key argument and no service-principal env vars in a non-interactive environment (container, CI) where DefaultAzureCredential also finds nothing (no managed identity, no az login). Common when running locally-configured code in Docker or a fresh VM.

Common situations: Works on dev laptop (az CLI login feeds DefaultAzureCredential) but fails in CI/containers; AZURE_CLIENT_SECRET rotated but old value still in env; tenant id mistaken for subscription id; secret env vars stripped by a secrets policy.

Related errors


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