{"record":{"id":"a350a869c24c2692","repo":"moeru-ai/airi","slug":"failed-to-initialize-speech-provider-a350a8","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/deepgram-tts.vue","lineNumber":33,"sourceCode":"const defaultModel = 'aura-2-thalia-en'\n\nconst defaultVoiceSettings = {}\n\nconst speechStore = useSpeechStore()\nconst providersStore = useProviderStore()\nconst providerStore = useProviderConfigStore()\nconst { configs: providers } = storeToRefs(providerStore)\n\nconst apiKeyConfigured = computed(() => !!providers.value[providerId]?.apiKey)\n\nconst availableVoices = computed(() => {\n  return speechStore.availableVoices[providerId] || []\n})\n\nasync function handleGenerateSpeech(input: string, voiceId: string, _useSSML: boolean) {\n  const provider = await providersStore.getProviderInstance(providerId) as SpeechProviderWithExtraOptions<string>\n  if (!provider) {\n    throw new Error('Failed to initialize speech provider')\n  }\n\n  const providerConfig = providerStore.getProviderConfig(providerId)\n\n  const model = providerConfig.model as string | undefined || defaultModel\n\n  return await speechStore.speech(\n    provider,\n    model,\n    input,\n    voiceId,\n    {\n      ...providerConfig,\n      ...defaultVoiceSettings,\n    },\n  )\n}\n","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/moeru-ai/airi/blob/677329427f32468c74b17f3ec47eeca4e05bec65/packages/stage-pages/src/pages/settings/providers/speech/deepgram-tts.vue#L15-L51","documentation":"Thrown by the Deepgram TTS settings playground when `providersStore.getProviderInstance(providerId)` resolves to a falsy value. The store (packages/stage-ui/src/stores/providers/provider.ts:744) looks up the provider definition and calls its `createProvider(config)` factory, typed as returning a non-nullable ProviderInstance (packages/stage-ui/src/libs/providers/types.ts:199). This guard is therefore a runtime backstop: the Deepgram factory (built through the unspeech bridge) returned `undefined` instead of throwing, almost always because the saved config is incomplete (blank/whitespace API key).","triggerScenarios":"Clicking Generate in Settings → Providers → Deepgram TTS playground before a valid API key is saved; an API key stored as an empty or whitespace-only string (the store only throws 'Provider credentials ... not found' when the whole config object is absent, not when fields are blank); generating right after editing credentials while a stale falsy build result lingers in the per-session `providerInstanceCache`.","commonSituations":"User adds the provider but skips onboarding; user pasted a key with trailing spaces or cleared the field and saved; switching between API keys without restarting the app; environments where the unspeech bridge factory declines on empty strings rather than raising.","solutions":["Open Settings → Providers → Deepgram TTS and save a non-empty API key, then let the built-in validation pass.","Re-run the playground (or restart the app) so `getProviderInstance` rebuilds the instance from the fresh config instead of any cached falsy result.","Check the browser console for `Error creating provider instance for ...` — the underlying factory reason is logged just before this throw.","Verify the config actually persisted (provider config store) — an unsaved key leaves an empty object that passes the store's presence check but produces no instance.","If config is provably valid and it still fails, report it: a factory returning undefined violates the non-nullable `createProvider` contract."],"exampleFix":"// before\nconst provider = await providersStore.getProviderInstance(providerId) as SpeechProviderWithExtraOptions<string>\nif (!provider)\n  throw new Error('Failed to initialize speech provider')\n\n// after\nconst config = providerStore.getProviderConfig(providerId)\nif (!config?.apiKey?.trim())\n  throw new Error('Deepgram API key is empty. Save credentials in provider settings first.')\nconst provider = await providersStore.getProviderInstance(providerId) as SpeechProviderWithExtraOptions<string>\nif (!provider || typeof provider.speech !== 'function')\n  throw new Error('Deepgram factory returned no usable instance — check saved config and console logs')","handlingStrategy":"validation","validationCode":"const apiKeyConfigured = computed(() => !!providers.value[providerId]?.apiKey?.trim())\n// template: <SpeechPlayground :disabled=\"!apiKeyConfigured\" ... />\nif (!apiKeyConfigured.value)\n  throw new Error('Save a Deepgram API key before generating speech')","typeGuard":"function isSpeechProvider(v: unknown): v is SpeechProvider<string> {\n  return typeof v === 'object' && v !== null && typeof (v as SpeechProvider<string>).speech === 'function'\n}","tryCatchPattern":"try {\n  const provider = await providersStore.getProviderInstance(providerId)\n  ...\n}\ncatch (error) {\n  // Distinguish store failures (credentials/definition missing) from factory declines\n  errorMessage.value = error instanceof Error ? error.message : String(error)\n}","preventionTips":["Gate the Generate button on a non-empty trimmed API key computed, not just on config presence.","Run the provider's built-in config validation before first use.","Treat any falsy result from getProviderInstance as a bug to report — the type contract says non-nullable.","Keep credentials trimmed on save to avoid whitespace-only keys."],"tags":["speech","provider","initialization","api-key","deepgram"],"backgroundTag":"provider-instance-undefined","analyzedSha":"677329427f32468c74b17f3ec47eeca4e05bec65","analyzedAt":"2026-08-18T17:29:58.153Z","schemaVersion":2},"datasetVersion":"2026-08-23T16:17:53.355Z"}