{"record":{"id":"cea6fb9eccb96613","repo":"moeru-ai/airi","slug":"failed-to-initialize-speech-provider-cea6fb","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/mimo-audio-speech.vue","lineNumber":128,"sourceCode":"\nconst apiKeyConfigured = computed(() => !!providers.value[providerId]?.apiKey)\n\nonMounted(async () => {\n  ensureProviderConfig()\n\n  if (!config.value?.model) {\n    model.value = defaultModel\n  }\n\n  await providersStore.loadModelsForConfiguredProviders()\n  await providersStore.fetchModelsForProvider(providerId)\n  await speechStore.loadVoicesForProvider(providerId)\n})\n\nasync function handleGenerateSpeech(input: string, voiceId: string, _useSSML: boolean, modelId?: string) {\n  const provider = await providersStore.getProviderInstance<SpeechProvider<string>>(providerId)\n  if (!provider) {\n    throw new Error('Failed to initialize speech provider')\n  }\n\n  const providerConfig = providerStore.getProviderConfig(providerId)\n  const modelToUse = modelId || model.value || defaultModel\n  const requestConfig = {\n    ...providerConfig,\n    ...defaultVoiceSettings,\n    stylePrompt: stylePrompt.value,\n    voiceSample: voiceSample.value,\n  }\n\n  if (modelToUse === 'mimo-v2.5-tts-voiceclone' && !voiceSample.value.trim()) {\n    throw new Error('Voice clone model requires a base64 audio sample in data URI format.')\n  }\n\n  const voiceToUse = modelToUse === 'mimo-v2.5-tts-voiceclone'\n    ? voiceSample.value.trim()\n    : voiceId || (config.value?.voice || defaultVoice)","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/moeru-ai/airi/blob/677329427f32468c74b17f3ec47eeca4e05bec65/packages/stage-pages/src/pages/settings/providers/speech/mimo-audio-speech.vue#L110-L146","documentation":"Thrown by the MiMo audio speech playground when `getProviderInstance<SpeechProvider<string>>(providerId)` resolves falsy. The page loads models and voices on mount, but building the provider itself depends on the persisted MiMo config (API key). The store's own failures throw distinct errors ('Provider credentials ... not found' / 'Provider definition ... not found'), so this branch means the MiMo factory completed but returned `undefined` — a runtime contract violation triggered by incomplete config such as a blank key.","triggerScenarios":"Clicking Generate before the MiMo API key is saved; key saved as empty/whitespace string so the config object passes the store's presence check while the factory declines; generating during the onMounted model fetch while credentials were never entered.","commonSituations":"User expects the default model fallback (`modelToUse` falls back to `defaultModel`) to also cover auth; key expired/revoked and re-entered without saving; environment where the MiMo endpoint requires additional config the factory validates silently.","solutions":["Save a valid MiMo API key in the provider settings and confirm validation passes.","Reload the playground after saving so `getProviderInstance` rebuilds the instance.","Read the console: the store logs `Error creating provider instance for ...` right before this throw when the factory itself throws; absence of that log points to a silent undefined return.","Verify the saved model selection is one of the fetched MiMo models (voiceclone prerequisites are validated separately).","Report persistent falsy results with valid credentials as a factory bug."],"exampleFix":"// before\nconst provider = await providersStore.getProviderInstance<SpeechProvider<string>>(providerId)\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('MiMo API key is empty. Save it in provider settings first.')\nconst provider = await providersStore.getProviderInstance<SpeechProvider<string>>(providerId)\nif (!provider || typeof provider.speech !== 'function')\n  throw new Error('MiMo factory returned no usable instance — check config and console logs')","handlingStrategy":"validation","validationCode":"const apiKeyConfigured = computed(() => !!providers.value[providerId]?.apiKey?.trim())\nif (!apiKeyConfigured.value)\n  throw new Error('Save a MiMo 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 { const provider = await providersStore.getProviderInstance<SpeechProvider<string>>(providerId) }\ncatch (error) { showError(errorMessageFrom(error)) }","preventionTips":["Save and validate the key before first synthesis.","Keep speech and transcription provider entries both configured when using MiMo for both.","Check voiceclone prerequisites (voice sample) separately from provider init."],"tags":["speech","provider","initialization","api-key","mimo"],"backgroundTag":"provider-instance-undefined","analyzedSha":"677329427f32468c74b17f3ec47eeca4e05bec65","analyzedAt":"2026-08-18T17:29:58.153Z","schemaVersion":2},"datasetVersion":"2026-08-23T16:17:53.355Z"}