{"record":{"id":"8246a879ef44373e","repo":"Hmbown/CodeWhale","slug":"model-model-requires-cloned-voice-data-pass","errorCode":null,"errorMessage":"Model '{model}' requires cloned voice data. Pass --clone-voice <mp3|wav> or --voice <data-uri>.","messagePattern":"Model '(.+?)' requires cloned voice data\\. Pass --clone-voice <mp3\\|wav> or --voice <data-uri>\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/client.rs","lineNumber":2373,"sourceCode":"        let instruction = request\n            .instruction\n            .as_deref()\n            .map(str::trim)\n            .filter(|value| !value.is_empty());\n        let voice = request\n            .voice\n            .as_deref()\n            .map(str::trim)\n            .filter(|value| !value.is_empty())\n            .map(str::to_string);\n\n        if model_lower.contains(\"voicedesign\") && instruction.is_none() {\n            anyhow::bail!(\n                \"Model '{model}' requires a voice design prompt. Pass --voice-prompt or --instruction.\"\n            );\n        }\n        if model_lower.contains(\"voiceclone\") && voice.is_none() {\n            anyhow::bail!(\n                \"Model '{model}' requires cloned voice data. Pass --clone-voice <mp3|wav> or --voice <data-uri>.\"\n            );\n        }\n\n        let mut audio = json!({\n            \"format\": audio_format.clone(),\n        });\n        if let Some(voice) = voice.as_deref() {\n            audio[\"voice\"] = json!(voice);\n        }\n\n        let body = build_speech_synthesis_body(&model, &text, instruction, audio);\n\n        let url = api_url(&self.base_url, \"chat/completions\");\n        let response = self.send_json_with_retry(&url, &body).await?;\n        let status = response.status();\n        if !status.is_success() {\n            let raw_error_text = bounded_error_text(response, ERROR_BODY_MAX_BYTES).await;","sourceCodeStart":2355,"sourceCodeEnd":2391,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/client.rs#L2355-L2391","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"# before\n/speech --model mimo-voiceclone-v1 \"hello world\"\n# after\n/speech --model mimo-voiceclone-v1 --clone-voice my-voice.mp3 \"hello world\"","handlingStrategy":"validation","validationCode":"fn voiceclone_needs_voice(model: &str, voice: Option<&str>) -> bool {\n    model.to_ascii_lowercase().contains(\"voiceclone\")\n        && voice.map(str::trim).filter(|s| !s.is_empty()).is_none()\n}","typeGuard":"enum SpeechModelKind { Plain, VoiceDesign, VoiceClone }\nfn speech_model_kind(model: &str) -> SpeechModelKind {\n    let m = model.to_ascii_lowercase();\n    if m.contains(\"voicedesign\") { SpeechModelKind::VoiceDesign }\n    else if m.contains(\"voiceclone\") { SpeechModelKind::VoiceClone }\n    else { SpeechModelKind::Plain }\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["speech","tts","validation","voice-clone","xiaomi-mimo"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}