{"record":{"id":"51ec4d88d813abaf","repo":"Hmbown/CodeWhale","slug":"speech-requires-a-tts-model-examples-got-m","errorCode":null,"errorMessage":"speech requires a TTS model (examples: {}); got {model}","messagePattern":"speech requires a TTS model \\(examples: (.+?)\\); got (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/lib.rs","lineNumber":7378,"sourceCode":"\n    if text.trim().is_empty() {\n        bail!(\"Speech text cannot be empty\");\n    }\n    let voice_is_data_uri = voice\n        .as_deref()\n        .map(str::trim)\n        .is_some_and(|value| value.starts_with(\"data:audio/\"));\n    if clone_voice.is_some() && voice.is_some() {\n        bail!(\"Use either --clone-voice or --voice for cloned voice data, not both\");\n    }\n    let model = infer_speech_model(\n        model.as_deref(),\n        clone_voice.is_some() || voice_is_data_uri,\n        voice_prompt.is_some(),\n    );\n    let model_lower = model.to_ascii_lowercase();\n    if !model_lower.contains(\"tts\") {\n        bail!(\n            \"speech requires a TTS model (examples: {}); got {model}\",\n            SPEECH_MODEL_EXAMPLES.join(\", \")\n        );\n    }\n    let is_voice_design = model_lower.contains(\"voicedesign\");\n    let is_voice_clone = model_lower.contains(\"voiceclone\");\n\n    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","sourceCodeStart":7360,"sourceCodeEnd":7396,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/lib.rs#L7360-L7396","documentation":"Model sanity check for speech: infer_speech_model() resolves the model (an explicit `--model` normalized for Xiaomi MiMo, or an inferred default from --clone-voice/--voice-prompt), and the resolved name must contain \"tts\" (lowercased substring test). Any other value — typically a chat model name typed into `--model` — is rejected with the list of valid examples before a request is made.","triggerScenarios":"Passing an explicit `--model` whose (normalized) name lacks \"tts\", e.g. `--model mimo-v2.5` or a DeepSeek chat model. Omitting --model never triggers this: inference yields mimo-v2.5-tts, mimo-v2.5-tts-voiceclone, or mimo-v2.5-tts-voicedesign.","commonSituations":"Reusing a chat model name from muscle memory; a typo in the model string; scripts where MODEL was set for coding, not speech.","solutions":["Use one of the TTS models: mimo-v2.5-tts, mimo-v2.5-tts-voicedesign, mimo-v2.5-tts-voiceclone, or mimo-v2-tts","Or omit `--model` entirely and let the CLI infer it from --clone-voice / --voice-prompt","Check the exact string for typos — the match is a substring test on the lowercased name"],"exampleFix":"// before\n$ codewhale speech --model mimo-v2.5 ...\nError: speech requires a TTS model (examples: mimo-v2.5-tts, ...); got mimo-v2.5\n\n// after\n$ codewhale speech --model mimo-v2.5-tts ...\n// or drop --model: the right TTS variant is inferred from the flags","handlingStrategy":"validation","validationCode":"# mirror the CLI check before invoking\nm=$(printf '%s' \"$MODEL\" | tr '[:upper:]' '[:lower:]')\ncase \"$m\" in *tts*) ;; *) echo \"not a TTS model: $MODEL\" >&2; exit 2;; esac","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep speech models in a dedicated variable; never share the chat MODEL var","Prefer omitting --model so inference picks a valid TTS variant"],"tags":["speech","tts","model-name","validation"],"backgroundTag":"unsupported-model","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}