moeru-ai/airi · error · Error

Voice clone model requires a base64 audio sample in data URI

Error message

Voice clone model requires a base64 audio sample in data URI format.

What it means

Guard in the MiMo speech playground: selecting the `mimo-v2.5-tts-voiceclone` model switches the voice source from a catalogue voice id to a user-provided cloned-voice sample, which must be base64 audio embedded as a data URI (`voiceSample`). The code checks `!voiceSample.value.trim()` for exactly that model id and throws this validation error before calling `speechStore.speech`, so no network request is wasted on a request the backend would reject.

Source

Thrown at packages/stage-pages/src/pages/settings/providers/speech/mimo-audio-speech.vue:141

})

async function handleGenerateSpeech(input: string, voiceId: string, _useSSML: boolean, modelId?: string) {
  const provider = await providersStore.getProviderInstance<SpeechProvider<string>>(providerId)
  if (!provider) {
    throw new Error('Failed to initialize speech provider')
  }

  const providerConfig = providerStore.getProviderConfig(providerId)
  const modelToUse = modelId || model.value || defaultModel
  const requestConfig = {
    ...providerConfig,
    ...defaultVoiceSettings,
    stylePrompt: stylePrompt.value,
    voiceSample: voiceSample.value,
  }

  if (modelToUse === 'mimo-v2.5-tts-voiceclone' && !voiceSample.value.trim()) {
    throw new Error('Voice clone model requires a base64 audio sample in data URI format.')
  }

  const voiceToUse = modelToUse === 'mimo-v2.5-tts-voiceclone'
    ? voiceSample.value.trim()
    : voiceId || (config.value?.voice || defaultVoice)

  return await speechStore.speech(
    provider,
    modelToUse,
    input,
    voiceToUse,
    requestConfig,
  )
}

const {
  isValidating,
  isValid,

View on GitHub (pinned to 677329427f)

Solutions

  1. Record or paste a base64 data-URI audio sample into the voice sample field before generating with the voiceclone model.
  2. Or switch the model selector back to a non-clone MiMo TTS model and pick a normal voice id.
  3. Ensure the sample is a full data URI (`data:audio/webm;base64,...` or similar), not bare base64, to avoid the next failure downstream.
  4. If cloning is unintended, clear the stored model so it falls back to the default non-clone model.

Example fix

// before
if (modelToUse === 'mimo-v2.5-tts-voiceclone' && !voiceSample.value.trim())
  throw new Error('Voice clone model requires a base64 audio sample in data URI format.')

// after (surface it in the UI instead of only throwing at generate time)
const voiceCloneReady = computed(() => modelToUse.value !== 'mimo-v2.5-tts-voiceclone' || !!voiceSample.value.trim())
// template: <button :disabled="!voiceCloneReady">Generate</button>
if (modelToUse === 'mimo-v2.5-tts-voiceclone' && !voiceSample.value.trim())
  throw new Error('Voice clone model requires a base64 audio sample in data URI format.')
Defensive patterns

Strategy: validation

Validate before calling

const isVoiceCloneModel = (id: string) => id === 'mimo-v2.5-tts-voiceclone'
const isDataUri = (s: string) => /^data:audio\/[a-z0-9.+-]+;base64,\S+$/i.test(s.trim())
const voiceCloneReady = computed(() =>
  !isVoiceCloneModel(model.value) || isDataUri(voiceSample.value),
)
// template: <button :disabled="!voiceCloneReady">Generate</button>

Type guard

function isVoiceCloneRequestReady(modelId: string, sample: string): boolean {
  return modelId !== 'mimo-v2.5-tts-voiceclone' || isDataUri(sample)
}

Try / catch

try { return await speechStore.speech(provider, modelToUse, input, voiceToUse, requestConfig) }
catch (error) {
  // keep the thrown validation message user-facing: it explains exactly what to provide
  showError(errorMessageFrom(error))
}

Prevention

When it happens

Trigger: Choosing `mimo-v2.5-tts-voiceclone` in the model dropdown and pressing Generate without having recorded/pasted a voice sample; voice sample field cleared after switching models; sample containing only whitespace; pasting raw base64 without the `data:audio/...;base64,` prefix (passes the blank check but fails downstream) — this specific message, however, is only the empty-sample case.

Common situations: Users assume voice cloning works from the text prompt or `stylePrompt` alone; switching from a normal TTS model where voice selection comes from the voice list; UI flows that forget to surface the sample input for the clone model.

Related errors


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