microsoft/semantic-kernel · error · Exception

Failed to get ephemeral token: {error_text}

Error message

Failed to get ephemeral token: {error_text}

What it means

Raised inside AzureRealtimeWebRTC._get_ephemeral_token when the HTTP POST to the Azure Realtime client_secrets endpoint returns a status code outside [200, 201]. The response body text is captured as error_text and interpolated into the message. This is a runtime/network error distinct from initialization errors — it fires during session setup, not construction. The exception is logged via logger.error and re-raised.

Source

Thrown at python/semantic_kernel/connectors/ai/open_ai/services/azure_realtime.py:367

        OpenAI's {"client_secret": {"value": "..."}}.
        See: https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/realtime-audio-webrtc
        """
        data = {
            "session": {
                "type": "realtime",
                "model": self.ai_model_id,
            }
        }
        headers, url = self._get_ephemeral_token_headers_and_url()
        headers = prepend_semantic_kernel_to_user_agent(headers)
        try:
            async with (
                ClientSession() as session,
                session.post(url, headers=headers, json=data) as response,
            ):
                if response.status not in [200, 201]:
                    error_text = await response.text()
                    raise Exception(f"Failed to get ephemeral token: {error_text}")

                result = await response.json()
                # Azure GA format returns {"value": "token"} directly
                return result["value"]

        except Exception as e:
            logger.error(f"Failed to get ephemeral token: {e!s}")
            raise

    @override
    def _get_webrtc_url(self) -> str:
        """Get the WebRTC URL.

        Uses the GA endpoint format: /openai/v1/realtime/calls
        See: https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/realtime-audio-webrtc
        """
        endpoint = str(self.client._base_url).rstrip("/")  # type: ignore[attr-defined]
        if "/openai" in endpoint:

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Read the full error_text in the exception message — it contains Azure's JSON error body with the specific failure reason (e.g. 'DeploymentNotFound', 'accessDenied').
  2. Verify the deployment name matches a deployment configured for the Realtime API in Azure Portal.
  3. If using an AD token, ensure it has not expired — tokens typically last ~1 hour; refresh and reconstruct if needed.
  4. For 429 responses, implement exponential backoff retry on the session creation call.
  5. Confirm the Azure resource is in a region that supports the Realtime API.

Example fix

# before — no error handling around session creation
await service.create_session(chat_history=history)

# after — catch and inspect the error, retry on transient failures
import asyncio
from semantic_kernel.exceptions.service_exceptions import ServiceInitializationError

for attempt in range(3):
    try:
        await service.create_session(chat_history=history)
        break
    except Exception as e:
        if '429' in str(e) and attempt < 2:
            await asyncio.sleep(2 ** attempt)
            continue
        raise
Defensive patterns

Strategy: retry

Try / catch

import asyncio
import logging

logger = logging.getLogger(__name__)

async def create_realtime_session_with_retry(service, chat_history=None, max_retries=3):
    for attempt in range(max_retries):
        try:
            await service.create_session(chat_history=chat_history)
            return
        except Exception as e:
            error_msg = str(e)
            # Parse Azure error status from the interpolated message
            if '429' in error_msg and attempt < max_retries - 1:
                wait = 2 ** attempt
                logger.warning(f'Rate limited, retrying in {wait}s (attempt {attempt + 1})')
                await asyncio.sleep(wait)
                continue
            if '5' in error_msg[:1] and attempt < max_retries - 1:
                await asyncio.sleep(2 ** attempt)
                continue
            logger.error(f'Failed to get ephemeral token: {error_msg}')
            raise

Prevention

When it happens

Trigger: Calling _get_ephemeral_token (typically during WebRTC session creation) when the Azure endpoint returns an error: 401/403 (invalid or expired credentials), 404 (deployment not found or realtime not enabled for the resource), 429 (rate limit), or 5xx (Azure service error). The error_text contains Azure's JSON error response body.

Common situations: Expired Azure AD token used for the request; deployment name does not match an actual deployment in the Azure resource; realtime API not enabled in the subscription/region; API key was rotated and the old one is now invalid; transient Azure outage or throttling.

Related errors


AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13). Data as JSON: /api/errors/1b0624bdc7b67b53. Report an issue: GitHub.