{"record":{"id":"a0344a9117d31b92","repo":"moeru-ai/airi","slug":"mimo-voice-clone-requires-a-base64-audio-sample-in","errorCode":null,"errorMessage":"MiMo voice clone requires a base64 audio sample in data URI format.","messagePattern":"MiMo voice clone requires a base64 audio sample in data URI format\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/stage-ui/src/libs/providers/providers/mimo-audio/index.ts","lineNumber":88,"sourceCode":"          input?: string\n          model?: string\n          response_format?: string\n          style_prompt?: string\n          voice_sample?: string\n          voice?: string\n        }\n        const model = body.model || defaultModel\n        const format = body.response_format || defaultFormat\n        const stylePrompt = body.style_prompt?.trim() || config.stylePrompt?.trim() || ''\n        const voiceSample = body.voice_sample?.trim() || config.voiceSample?.trim() || ''\n        const userPrompt = model === 'mimo-v2.5-tts-voiceclone'\n          ? stylePrompt\n          : stylePrompt || 'Use a natural, clear speaking style.'\n\n        const audio: Record<string, string> = { format }\n        if (model === 'mimo-v2.5-tts-voiceclone') {\n          if (!voiceSample)\n            throw new Error('MiMo voice clone requires a base64 audio sample in data URI format.')\n          audio.voice = voiceSample\n        }\n        else if (model === 'mimo-v2.5-tts') {\n          audio.voice = body.voice || defaultVoice\n        }\n\n        if (model === 'mimo-v2.5-tts-voicedesign' && !stylePrompt)\n          throw new Error('MiMo voice design requires a style prompt in the user message.')\n\n        const response = await fetch(new URL('chat/completions', baseUrl), {\n          method: 'POST',\n          headers: { 'Content-Type': 'application/json', 'api-key': apiKey },\n          body: JSON.stringify({\n            model,\n            messages: [\n              { role: 'user', content: userPrompt },\n              { role: 'assistant', content: body.input ?? '' },\n            ],","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/moeru-ai/airi/blob/677329427f32468c74b17f3ec47eeca4e05bec65/packages/stage-ui/src/libs/providers/providers/mimo-audio/index.ts#L70-L106","documentation":"When the request selects the mimo-v2.5-tts-voiceclone model, the provider requires a voice sample: it falls back from body.voice_sample to config.voiceSample (both trimmed) and throws if neither is present. The sample must be a base64 data URI of reference audio; the check runs client-side before the HTTP request is built.","triggerScenarios":"Voice-clone model selected but no sample was recorded or uploaded in the UI; the sample exists only in provider settings that were never saved; a whitespace-only sample string; a UI flow that passes only the named-voice `voice` field while the model is voiceclone.","commonSituations":"User skips the recording step; the sample upload silently failed; a different model was configured in settings but the request overrides the model to voiceclone without supplying the sample.","solutions":["Record or upload a reference clip and pass it as voice_sample (base64 data URI), or save it as the provider's voiceSample setting","Switch to mimo-v2.5-tts if no sample is available and a named voice is acceptable","Validate in the UI that the sample exists before allowing the voiceclone model","Trim and sanity-check the data URI prefix before sending"],"exampleFix":"// before\nspeech({ model: 'mimo-v2.5-tts-voiceclone', input: text }) // no voice_sample → throw\n\n// after\nspeech({ model: 'mimo-v2.5-tts-voiceclone', input: text, voice_sample: recordedDataUri })","handlingStrategy":"validation","validationCode":"const isAudioDataUri = (v: string) => /^data:audio\\/[a-z0-9.+-]+;base64,/.test(v.trim())\nif (model === 'mimo-v2.5-tts-voiceclone' && !isAudioDataUri(voiceSample))\n  promptForVoiceSample()","typeGuard":"function isAudioDataUri(value: string): boolean {\n  return /^data:audio\\/[a-z0-9.+-]+;base64,[A-Za-z0-9+/=]+$/.test(value.trim())\n}","tryCatchPattern":"try {\n  await synthesize(text, { model: 'mimo-v2.5-tts-voiceclone', voice_sample: sample })\n}\ncatch (err) {\n  if (err.message.includes('voice clone'))\n    openVoiceRecorderStep()\n}","preventionTips":["Gate the voiceclone option behind a completed recording step","Persist the sample in provider settings after first successful use","Check the data URI prefix on both sides before sending"],"tags":["mimo","tts","voice-clone","validation","precondition"],"backgroundTag":"missing-required-parameter","analyzedSha":"677329427f32468c74b17f3ec47eeca4e05bec65","analyzedAt":"2026-08-18T17:29:58.153Z","schemaVersion":2},"datasetVersion":"2026-08-23T16:17:53.355Z"}