{"record":{"id":"679877ada8930b7a","repo":"Hmbown/CodeWhale","slug":"mimo-v2-5-tts-voiceclone-requires-clone-voice-m","errorCode":null,"errorMessage":"mimo-v2.5-tts-voiceclone requires --clone-voice <mp3|wav> or --voice <data-uri>","messagePattern":"mimo-v2\\.5-tts-voiceclone requires --clone-voice <mp3\\|wav> or --voice <data-uri>","errorType":"error_code","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/lib.rs","lineNumber":7853,"sourceCode":"    let instruction = combine_speech_instructions(instruction, voice_prompt);\n    if is_voice_design\n        && instruction\n            .as_deref()\n            .is_none_or(|value| value.trim().is_empty())\n    {\n        bail!(\n            \"mimo-v2.5-tts-voicedesign requires --voice-prompt or --instruction to describe the voice\"\n        );\n    }\n\n    let voice = if let Some(clone_path) = clone_voice {\n        Some(encode_voice_clone_sample_data_uri(&clone_path)?)\n    } else if is_voice_design {\n        None\n    } else if let Some(value) = voice.filter(|value| !value.trim().is_empty()) {\n        Some(value)\n    } else if is_voice_clone {\n        bail!(\"mimo-v2.5-tts-voiceclone requires --clone-voice <mp3|wav> or --voice <data-uri>\");\n    } else {\n        Some(DEFAULT_VOICE.to_string())\n    };\n    let format = normalize_speech_format(&format).with_context(|| {\n        format!(\"Unsupported speech format '{format}' (allowed: wav, mp3, pcm16)\")\n    })?;\n    let output = output.unwrap_or_else(|| {\n        output_dir\n            .or_else(|| config.speech_output_dir())\n            .unwrap_or_default()\n            .join(default_speech_output_name(&format))\n    });\n\n    let client = CodewhaleClient::new(config)?;\n    let response = client\n        .synthesize_speech(SpeechSynthesisRequest {\n            model: model.clone(),\n            text,","sourceCodeStart":7835,"sourceCodeEnd":7871,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/lib.rs#L7835-L7871","documentation":"The TUI's speech-synthesis path rejects a voice-clone request that arrives without any voice source. When the target model is mimo-v2.5-tts-voiceclone, it needs either a local mp3/wav sample (--clone-voice, converted to a data URI) or an explicit --voice data URI; with neither, it bails instead of sending a request the provider would reject.","triggerScenarios":"Calling the TTS/voice-clone flow with model mimo-v2.5-tts-voiceclone and no --clone-voice file, plus a --voice value that is empty or whitespace-only, so the else-if chain falls through to the voice-clone bail.","commonSituations":"Users switch the speech model to voiceclone but forget to pass --clone-voice; a shell variable holding the voice value expands empty; an old config omits the voice field after migrating to the voiceclone model.","solutions":["Pass --clone-voice path/to/sample.mp3 (or .wav) with the voice-clone model","Or pass --voice with a non-empty data URI","Or use the default voice model if you don't need cloning"],"exampleFix":"// before\ncodewhale --model mimo-v2.5-tts-voiceclone --say hi\n// after\ncodewhale --model mimo-v2.5-tts-voiceclone --clone-voice my-voice.wav --say hi","handlingStrategy":"validation","validationCode":"if model == \"mimo-v2.5-tts-voiceclone\" && clone_path.is_none() && voice.as_deref().map_or(true, |v| v.trim().is_empty()) { eprintln!(\"voiceclone requires --clone-voice or --voice\"); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pair the voiceclone model with --clone-voice","Check that the voice variable is non-empty before building the command"],"tags":["cli","voice-clone","tts","missing-argument"],"backgroundTag":"missing-required-argument","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}