Hmbown/CodeWhale · error · anyhow::Error
speech requires a TTS model
Error message
speech requires a TTS model (examples: {}); got {model} What it means
The speech subcommand requires a text-to-speech model; after inferring the model (from --model or defaults based on voice/voice-prompt usage), it checks the lowercase model name contains "tts" and bails otherwise, listing example TTS model names from SPEECH_MODEL_EXAMPLES.
Solutions
- Pass an explicit TTS model via --model (see the example names in the error message)
- Use a model name containing "tts", e.g. mimo-v2.5-tts or the voicedesign/voiceclone variants
- Fix the config default model so it does not supply a chat model to speech
Example fix
// before codewhale speech --model mimo-v2.5 --text "hi" // after codewhale speech --model mimo-v2.5-tts --text "hi"
Defensive patterns
Strategy: validation
Validate before calling
if !model.to_ascii_lowercase().contains("tts") {
eprintln!("speech requires a TTS model, got {model}");
std::process::exit(2);
} Prevention
- Keep a constant list of valid TTS model ids in tooling
- Never reuse chat model defaults for the speech subcommand
- Validate --model values against SPEECH_MODEL_EXAMPLES in CI scripts
When it happens
Trigger: Passing --model with a non-TTS model name (e.g. a chat model like mimo-v2.5) to `speech`, or a config default model that is not a TTS model.
Common situations: Reusing a chat model name from the speech command line; typos in the TTS model id; stale config defaults where the general model leaks into the speech command.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Model ' ' requires a voice design prompt. Pass…
- Model name cannot be empty
- Speech text cannot be empty
- A positive pull request number is required
- API key contains invalid control characters
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/51ec4d88d813abaf.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/lib.rs:7827
if text.trim().is_empty() {
bail!("Speech text cannot be empty");
}
let voice_is_data_uri = voice
.as_deref()
.map(str::trim)
.is_some_and(|value| value.starts_with("data:audio/"));
if clone_voice.is_some() && voice.is_some() {
bail!("Use either --clone-voice or --voice for cloned voice data, not both");
}
let model = infer_speech_model(
model.as_deref(),
clone_voice.is_some() || voice_is_data_uri,
voice_prompt.is_some(),
);
let model_lower = model.to_ascii_lowercase();
if !model_lower.contains("tts") {
bail!(
"speech requires a TTS model (examples: {}); got {model}",
SPEECH_MODEL_EXAMPLES.join(", ")
);
}
let is_voice_design = model_lower.contains("voicedesign");
let is_voice_clone = model_lower.contains("voiceclone");
let instruction = combine_speech_instructions(instruction, voice_prompt);
if is_voice_design
&& instruction
.as_deref()
.is_none_or(|value| value.trim().is_empty())
{
bail!(
"mimo-v2.5-tts-voicedesign requires --voice-prompt or --instruction to describe the voice"
);
}
View on GitHub (pinned to 73e0f67d83)