BerriAI/litellm · error · AzureSpeechAudioTranscriptionException

Azure AI Speech transcription requires a Cognitive Services

Error message

Azure AI Speech transcription requires a Cognitive Services or STT Speech endpoint, not an Azure OpenAI endpoint.

What it means

LiteLLM resolves the Azure Speech base URL from the hostname of your `api_base`. If the hostname is recognized as an Azure OpenAI endpoint (e.g. <resource>.openai.azure.com) it raises this 400, because Azure AI Speech transcription calls the Speech/Cognitive Services API, not the Azure OpenAI audio API. This guard prevents a guaranteed-to-fail request (wrong API surface, wrong auth header).

Source

Thrown at litellm/llms/azure/audio_transcription/transformation.py:163

            message=error_message,
            status_code=status_code,
            headers=headers,
        )

    def _resolve_stt_base_url(self, api_base: str) -> str:
        api_base = api_base.rstrip("/")
        parsed_url: Final = urlparse(api_base)
        hostname: Final = parsed_url.hostname or ""

        if self._is_cognitive_services_endpoint(hostname=hostname):
            region: Final = self._extract_region_from_hostname(hostname=hostname, domain=self.COGNITIVE_SERVICES_DOMAIN)
            return self._build_stt_base_url(region=region)

        if self._is_stt_endpoint(hostname=hostname):
            return f"{parsed_url.scheme}://{hostname}"

        if self._is_azure_openai_endpoint(hostname=hostname):
            raise AzureSpeechAudioTranscriptionException(
                message=(
                    "Azure AI Speech transcription requires a Cognitive Services "
                    "or STT Speech endpoint, not an Azure OpenAI endpoint."
                ),
                status_code=400,
            )

        return api_base

    def _is_cognitive_services_endpoint(self, hostname: str) -> bool:
        return hostname == self.COGNITIVE_SERVICES_DOMAIN or hostname.endswith(f".{self.COGNITIVE_SERVICES_DOMAIN}")

    def _is_stt_endpoint(self, hostname: str) -> bool:
        return hostname == self.STT_SPEECH_DOMAIN or hostname.endswith(f".{self.STT_SPEECH_DOMAIN}")

    def _is_azure_openai_endpoint(self, hostname: str) -> bool:
        return hostname.endswith(".openai.azure.com")

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Switch api_base to your Speech resource endpoint: https://{region}.api.cognitive.microsoft.com or https://{region}.stt.speech.microsoft.com.
  2. If you actually want Azure OpenAI Whisper, use an azure/ deployment model name routed to Azure OpenAI instead of the Azure Speech integration.
  3. Create a Speech resource in the Azure portal if none exists and copy its endpoint.

Example fix

# before
litellm.transcription(model='azure/speech', file=f, api_base='https://myres.openai.azure.com', api_key=key)

# after
litellm.transcription(model='azure/speech', file=f, api_base='https://eastus.api.cognitive.microsoft.com', api_key=key)
Defensive patterns

Strategy: validation

Validate before calling

from urllib.parse import urlparse

host = urlparse(api_base).hostname or ''
if host.endswith('openai.azure.com'):
    raise ValueError(f'{api_base} is an Azure OpenAI endpoint; use a Cognitive Services/STT endpoint for Speech transcription.')

Prevention

When it happens

Trigger: Passing api_base='https://myresource.openai.azure.com' (copied from an existing Azure OpenAI deployment) to a transcription call routed through the Azure Speech handler.

Common situations: Teams with existing Azure OpenAI deployments reuse that endpoint for transcription out of habit; config templates for Azure OpenAI chat are duplicated for speech without changing the endpoint; confusion because Azure OpenAI also offers whisper audio APIs.

Related errors


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