Error Handling

Handle API errors, empty responses, and other failure modes.

SpeechSDK provides typed error classes for common failure modes.

Error Classes

import {
  generateSpeech,
  ApiError,
  NoSpeechGeneratedError,
  SpeechSDKError,
} from "@speech-sdk/core"
ErrorWhen
ApiErrorProvider API returns a non-2xx response
NoSpeechGeneratedErrorProvider returned empty audio data
StreamingNotSupportedErrorstreamSpeech called on a model that has no streaming endpoint
TimestampKeyMissingErrortimestamps: true requested but the STT fallback API key is not configured
SpeechSDKErrorBase class for all SDK errors

Catching Errors

import { generateSpeech, ApiError, SpeechSDKError } from "@speech-sdk/core"

try {
  const result = await generateSpeech({
    model: "openai/gpt-4o-mini-tts",
    text: "Hello!",
    voice: "alloy",
  })
} catch (error) {
  if (error instanceof ApiError) {
    console.log(error.statusCode) // 401
    console.log(error.model) // "openai/gpt-4o-mini-tts"
    console.log(error.responseBody) // raw response from the API
  } else if (error instanceof SpeechSDKError) {
    console.log(error.message)
  }
}

ApiError

Thrown when the provider returns a non-2xx HTTP status. Contains details about what went wrong:

class ApiError extends SpeechSDKError {
  readonly statusCode: number // HTTP status code
  readonly responseBody?: unknown // Raw response body
  readonly model: string // Model string that was used
  readonly retryAfterMs?: number // Parsed Retry-After header (when present)
}

Common status codes:

  • 401 — Invalid or missing API key
  • 403 — Insufficient permissions
  • 429 — Rate limited (will be retried; see below)
  • 500 — Provider server error (will be retried)

NoSpeechGeneratedError

Thrown when the provider returns a successful response but the audio data is empty:

import { NoSpeechGeneratedError } from '@speech-sdk/core';

try {
  const result = await generateSpeech({ ... });
} catch (error) {
  if (error instanceof NoSpeechGeneratedError) {
    // Provider returned no audio — try a different model or voice
  }
}

TimestampKeyMissingError

Thrown when timestamps: true is requested but the SDK can't obtain word-level timestamps because the API key for the fallback STT provider is not set. The message names the env var that would unblock the request.

import { TimestampKeyMissingError } from "@speech-sdk/core"

try {
  await generateSpeech({
    model: "openai/gpt-4o-mini-tts",
    text: "Hello!",
    voice: "alloy",
    timestamps: true, // OpenAI TTS has no native alignment — needs STT fallback
  })
} catch (error) {
  if (error instanceof TimestampKeyMissingError) {
    // Set OPENAI_API_KEY (the default fallback) or pre-create the provider
    // client with `fallbackSTT` — see /docs/timestamps.
  }
}

The fallback defaults to OpenAI Whisper. Override it by passing fallbackSTT to the provider factory when you create the client — see the timestamps guide.

Retries

SpeechSDK automatically retries on 5xx errors (excluding 501), 429 rate limits, and network failures with exponential backoff and jitter (randomize: true). Other 4xx errors — like authentication failures — are not retried. Default: 2 retries.

// Increase retries for unreliable connections
const result = await generateSpeech({
  model: "openai/gpt-4o-mini-tts",
  text: "Hello!",
  voice: "alloy",
  maxRetries: 5,
})
// Disable retries
const result = await generateSpeech({
  model: "openai/gpt-4o-mini-tts",
  text: "Hello!",
  voice: "alloy",
  maxRetries: 0,
})

Rate Limits & Retry-After

429 responses are retried alongside 5xx. When the provider includes a Retry-After header, SpeechSDK honors both forms allowed by RFC 7231 §7.1.3delay-seconds (e.g. Retry-After: 30) and HTTP-date (e.g. Retry-After: Wed, 21 Oct 2026 07:28:00 GMT). The wait is capped at 60 seconds and gets +250 ms of jitter to avoid thundering-herd retries. The SDK subtracts p-retry's own backoff so total wait time targets the header value.

The parsed delay is exposed on ApiError.retryAfterMs whenever the header is present — even on terminal errors that exhaust retries or aren't retriable. Use it to decide whether to surface a message to the user, queue the request for later, or back off application-wide.

import { generateSpeech, ApiError } from "@speech-sdk/core"

try {
  await generateSpeech({
    model: "openai/gpt-4o-mini-tts",
    text: "Hello!",
    voice: "alloy",
  })
} catch (error) {
  if (error instanceof ApiError && error.statusCode === 429) {
    if (error.retryAfterMs != null) {
      // Provider asked us to wait this long. Schedule a follow-up.
      console.warn(`Rate limited. Retry after ${error.retryAfterMs} ms.`)
    } else {
      console.warn("Rate limited (no Retry-After header).")
    }
  }
}

On this page