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
- For quick testing, mint a token manually and pass it: az account get-access-token --resource 'https://ai.azure.com' then api_key=<token>.
- For production, set AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET for a service principal granted access to the Foundry project.
- If on an Azure VM/App Service, enable a managed identity and grant it the project role so DefaultAzureCredential works.
- 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
- Provision a service principal for non-interactive environments; never rely on az CLI login in prod.
- Cache and refresh tokens (they expire ~1h) when minting them yourself.
- Add a startup auth check that calls get_azure_ad_token once so failures surface at boot, not mid-request.
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
- {error_msg}: {response.text}
- Streaming request failed: {error_text.decode()}
- api_base is required for Azure AI Agents. Set it via AZURE_A
- api_key is None. Please set AZURE_AI_API_KEY or dynamically
- Azure AI API key is required for model {model}. Set AZURE_AI
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/3a152e146879f3f0.
Report an issue: GitHub.