Hmbown/CodeWhale · error
Model '{model}' requires cloned voice data. Pass --clone-voi
Error message
Model '{model}' requires cloned voice data. Pass --clone-voice <mp3|wav> or --voice <data-uri>. What it means
Model-specific validation in `synthesize_speech`: when the model id contains `voiceclone`, the request must carry cloned voice data — either a file via `--clone-voice <mp3|wav>` or a data-URI via `--voice <data-uri>`. The client checks `voice.is_none()` and rejects locally before building the request body, since the clone flow cannot proceed without source audio.
Source
Thrown at crates/tui/src/client.rs:2373
let instruction = request
.instruction
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty());
let voice = request
.voice
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty())
.map(str::to_string);
if model_lower.contains("voicedesign") && instruction.is_none() {
anyhow::bail!(
"Model '{model}' requires a voice design prompt. Pass --voice-prompt or --instruction."
);
}
if model_lower.contains("voiceclone") && voice.is_none() {
anyhow::bail!(
"Model '{model}' requires cloned voice data. Pass --clone-voice <mp3|wav> or --voice <data-uri>."
);
}
let mut audio = json!({
"format": audio_format.clone(),
});
if let Some(voice) = voice.as_deref() {
audio["voice"] = json!(voice);
}
let body = build_speech_synthesis_body(&model, &text, instruction, audio);
let url = api_url(&self.base_url, "chat/completions");
let response = self.send_json_with_retry(&url, &body).await?;
let status = response.status();
if !status.is_success() {
let raw_error_text = bounded_error_text(response, ERROR_BODY_MAX_BYTES).await;View on GitHub (pinned to 8880682c63)
Solutions
- Provide source audio: `--clone-voice recording.mp3` (or a .wav).
- Alternatively pass the voice payload directly as a data-URI with `--voice <data-uri>`.
- If you do not have reference audio, use a non-voiceclone model instead.
Example fix
# before /speech --model mimo-voiceclone-v1 "hello world" # after /speech --model mimo-voiceclone-v1 --clone-voice my-voice.mp3 "hello world"
Defensive patterns
Strategy: validation
Validate before calling
fn voiceclone_needs_voice(model: &str, voice: Option<&str>) -> bool {
model.to_ascii_lowercase().contains("voiceclone")
&& voice.map(str::trim).filter(|s| !s.is_empty()).is_none()
} Type guard
enum SpeechModelKind { Plain, VoiceDesign, VoiceClone }
fn speech_model_kind(model: &str) -> SpeechModelKind {
let m = model.to_ascii_lowercase();
if m.contains("voicedesign") { SpeechModelKind::VoiceDesign }
else if m.contains("voiceclone") { SpeechModelKind::VoiceClone }
else { SpeechModelKind::Plain }
} Prevention
- Verify the clone audio file exists and is mp3/wav before invoking the command.
- Offer a file picker for `--clone-voice` in the UI to avoid path typos producing empty payloads.
- Remember that whitespace-only `--voice` values are treated as absent — validate with trim.
When it happens
Trigger: Using a `*voiceclone*` model with neither `--clone-voice` nor `--voice` supplied; passing a `--voice` value that is only whitespace (trimmed and filtered, so treated as absent).
Common situations: Selecting the voice-clone model without a reference recording ready; assuming clone models fall back to a default voice; migrating a script from a plain TTS model to the clone model without adding the audio argument.
Related errors
- speech synthesis requires provider 'xiaomi-mimo' (current: {
- Model '{model}' requires a voice design prompt. Pass --voice
- Speech model cannot be empty
- Speech text cannot be empty
- Speech synthesis failed: HTTP {status}: {error_text}
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/8246a879ef44373e.
Report an issue: GitHub.