{"record":{"id":"81a51691e827cf0a","repo":"moeru-ai/airi","slug":"failed-to-initialize-speech-provider-81a516","errorCode":null,"errorMessage":"Failed to initialize speech provider","messagePattern":"Failed to initialize speech provider","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/stage-pages/src/pages/settings/providers/speech/microsoft-speech.vue","lineNumber":79,"sourceCode":"  if (!providers.value[providerId]?.region) {\n    if (!providers.value[providerId])\n      providers.value[providerId] = { region: region.value }\n    else\n      providers.value[providerId].region = region.value\n  }\n\n  await speechStore.loadVoicesForProvider(providerId)\n})\n\nwatch([apiKeyConfigured, region], async () => {\n  await speechStore.loadVoicesForProvider(providerId)\n})\n\n// Generate speech with Microsoft-specific parameters\nasync function handleGenerateSpeech(input: string, voiceId: string, useSSML: boolean) {\n  const provider = await providersStore.getProviderInstance(providerId) as SpeechProviderWithExtraOptions<string, UnMicrosoftOptions>\n  if (!provider) {\n    throw new Error('Failed to initialize speech provider')\n  }\n\n  // Get provider configuration\n  const providerConfig = providerStore.getProviderConfig(providerId)\n\n  // Get model from configuration or use default\n  const model = providerConfig.model as string | undefined || defaultModel\n\n  // For Microsoft Speech, we need to ensure we're using the right region\n  const options = {\n    ...providerConfig,\n    region: region.value,\n    disableSsml: !useSSML, // If useSSML is true, we don't disable SSML\n  }\n\n  // If not using SSML and we have a voice, generate SSML\n  if (!useSSML && voiceId) {\n    const voice = availableVoices.value.find(v => v.id === voiceId)","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/moeru-ai/airi/blob/677329427f32468c74b17f3ec47eeca4e05bec65/packages/stage-pages/src/pages/settings/providers/speech/microsoft-speech.vue#L61-L97","documentation":"Thrown by the Microsoft (Azure) Speech playground when the provider factory resolves falsy. The Microsoft provider is created through the unspeech bridge and needs both an API key and a region — the page injects the reactive `region` into the request options after building the instance. `getProviderInstance` types the result as non-nullable, so this guard fires when the factory declines on the persisted config (blank key, or a config shape the bridge refuses) rather than when the store's own missing-credentials/definition errors throw.","triggerScenarios":"Clicking Generate before saving the Azure Speech API key; key present but region never selected so the factory or first request path gets unusable config; whitespace-only credentials; stale falsy result reused within the same session cache.","commonSituations":"Confusing Azure region names or leaving region at its placeholder; using an Azure resource from a tier without Speech services enabled; rotating keys in the Azure portal without re-saving in AIRI; trying the playground before finishing onboarding.","solutions":["Save both the API key and a valid Azure region in Settings → Providers → Microsoft Speech, and let validation succeed.","Re-enter the playground after saving so the instance is rebuilt.","Check console for `Error creating provider instance for ...` for the bridge's underlying refusal reason.","Confirm the Azure resource is a Speech resource (not just OpenAI/Cognitive general) and its region matches.","If config is complete and valid, report the silent-undefined factory as a contract bug."],"exampleFix":"// before\nconst provider = await providersStore.getProviderInstance(providerId) as SpeechProviderWithExtraOptions<string, UnMicrosoftOptions>\nif (!provider)\n  throw new Error('Failed to initialize speech provider')\n\n// after\nconst config = providerStore.getProviderConfig(providerId)\nif (!config?.apiKey?.trim() || !region.value)\n  throw new Error('Microsoft Speech needs both an API key and a region. Save them in provider settings first.')\nconst provider = await providersStore.getProviderInstance(providerId) as SpeechProviderWithExtraOptions<string, UnMicrosoftOptions>\nif (!provider || typeof provider.speech !== 'function')\n  throw new Error('Microsoft Speech factory returned no usable instance — check key/region and console logs')","handlingStrategy":"validation","validationCode":"const canGenerate = computed(() =>\n  !!providers.value[providerId]?.apiKey?.trim() && !!region.value,\n)\nif (!canGenerate.value)\n  throw new Error('Microsoft Speech needs an API key and a region before generating')","typeGuard":"function isSpeechProvider(v: unknown): v is SpeechProviderWithExtraOptions<string, UnMicrosoftOptions> {\n  return typeof v === 'object' && v !== null && typeof (v as SpeechProviderWithExtraOptions<string>).speech === 'function'\n}","tryCatchPattern":"try { const provider = await providersStore.getProviderInstance(providerId) }\ncatch (error) { showError(errorMessageFrom(error)) }","preventionTips":["Persist region alongside the key so it survives reloads.","Use region ids exactly as Azure names them.","Re-validate after rotating keys in the Azure portal."],"tags":["speech","provider","initialization","api-key","region","microsoft-azure"],"backgroundTag":"provider-instance-undefined","analyzedSha":"677329427f32468c74b17f3ec47eeca4e05bec65","analyzedAt":"2026-08-18T17:29:58.153Z","schemaVersion":2},"datasetVersion":"2026-08-23T16:17:53.355Z"}