moeru-ai/airi · error · Error

Failed to initialize speech provider

Error message

Failed to initialize speech provider

What it means

Thrown by the ElevenLabs speech playground when `getProviderInstance('elevenlabs')` resolves falsy. The ElevenLabs definition (packages/stage-ui/src/libs/providers/providers/elevenlabs/index.ts:90) builds the instance via `createUnElevenLabs(config.apiKey.trim(), config.baseUrl ?? 'https://unspeech.hyp3r.link/v1/')`; although the static type says non-nullable, the underlying unspeech factory can yield `undefined` when the key is blank, and this page guard converts that into an explicit error before `speechStore.speech()` is called with a dead provider.

Source

Thrown at packages/stage-pages/src/pages/settings/providers/speech/elevenlabs.vue:55

const speechStore = useSpeechStore()
const providersStore = useProviderStore()
const providerStore = useProviderConfigStore()
const { configs: providers } = storeToRefs(providerStore)
const { t } = useI18n()

// Check if API key is configured
const apiKeyConfigured = computed(() => !!providers.value[providerId]?.apiKey)

// Get available voices for ElevenLabs
const availableVoices = computed(() => {
  return speechStore.availableVoices[providerId] || []
})

// Generate speech with ElevenLabs-specific parameters
async function handleGenerateSpeech(input: string, voiceId: string, _useSSML: boolean) {
  const provider = await providersStore.getProviderInstance(providerId) as SpeechProviderWithExtraOptions<string, UnElevenLabsOptions>
  if (!provider) {
    throw new Error('Failed to initialize speech provider')
  }

  // Get provider configuration
  const providerConfig = providerStore.getProviderConfig(providerId)

  // Get model from configuration or use default
  const model = providerConfig.model as string | undefined || defaultModel

  // ElevenLabs doesn't need SSML conversion, but if SSML is provided, use it directly
  return await speechStore.speech(
    provider,
    model,
    input,
    voiceId,
    {
      ...providerConfig,
      ...defaultVoiceSettings,
    },

View on GitHub (pinned to 677329427f)

Solutions

  1. Save a valid ElevenLabs API key in Settings → Providers → ElevenLabs and pass the built-in validators (they require apiKey and an absolute baseUrl with trailing slash when overridden).
  2. Reload the settings page after saving so `getProviderInstance` builds from current config.
  3. Inspect console output for `Error creating provider instance for elevenlabs:` preceding this throw.
  4. If a custom baseUrl is set, confirm it is absolute with a trailing slash — the validator flags that separately but the factory can also fail on it.
  5. Treat persistent falsy results with a valid key as a factory bug (contract violation) and report it upstream.

Example fix

// before
const provider = await providersStore.getProviderInstance(providerId) as SpeechProviderWithExtraOptions<string, UnElevenLabsOptions>
if (!provider)
  throw new Error('Failed to initialize speech provider')

// after
const config = providerStore.getProviderConfig(providerId)
if (!config?.apiKey?.trim())
  throw new Error('ElevenLabs API key is empty. Save it in provider settings first.')
const provider = await providersStore.getProviderInstance(providerId) as SpeechProviderWithExtraOptions<string, UnElevenLabsOptions>
if (!provider || typeof provider.speech !== 'function')
  throw new Error('ElevenLabs factory returned no usable instance — check key/baseUrl and console logs')
Defensive patterns

Strategy: validation

Validate before calling

const canGenerate = computed(() => {
  const c = providers.value[providerId]
  return !!c?.apiKey?.trim() && (!c?.baseUrl || /^https?:\/\/.+\/$/.test(c.baseUrl.trim()))
})

Type guard

function isSpeechProvider(v: unknown): v is SpeechProviderWithExtraOptions<string, UnElevenLabsOptions> {
  return typeof v === 'object' && v !== null && typeof (v as SpeechProviderWithExtraOptions<string>).speech === 'function'
}

Try / catch

try { const provider = await providersStore.getProviderInstance(providerId) }
catch (error) { // store-level: credentials/definition missing — surface message directly
  showError(errorMessageFrom(error)) }

Prevention

When it happens

Trigger: Clicking Generate with `providers.value.elevenlabs.apiKey` empty or whitespace; config saved with a key but the unspeech factory silently declining it; baseUrl left unset is fine (it falls back to the unspeech bridge) — the failing input is the missing key.

Common situations: Trying the playground before finishing provider setup; clearing the key field and saving; copy/pasting a key with quotes or spaces so `.trim()` yields an unusable credential; stale page state after revoking a key in the ElevenLabs dashboard.

Related errors


AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18). Data as JSON: /api/errors/1872f445f6352c51. Report an issue: GitHub.