Hmbown/CodeWhale · error
unsupported voice clone sample extension '{other}'. Use .mp3
Error message
unsupported voice clone sample extension '{other}'. Use .mp3 or .wav. What it means
voice_clone_data_uri_from_bytes maps the sample's file extension to a MIME type and supports only .mp3 (audio/mpeg) and .wav (audio/wav). Any other extension, including no extension at all (the extension defaults to empty), is rejected because the provider needs a concrete audio MIME type in the data URI.
Source
Thrown at crates/tui/src/tools/speech.rs:421
fn voice_clone_data_uri_from_bytes(path: &Path, bytes: &[u8]) -> anyhow::Result<String> {
let base64_audio = general_purpose::STANDARD.encode(bytes);
if base64_audio.len() > VOICE_CLONE_BASE64_MAX_BYTES {
anyhow::bail!(
"voice clone sample is too large after base64 encoding ({} bytes > 10 MB)",
base64_audio.len()
);
}
let extension = path
.extension()
.and_then(|value| value.to_str())
.unwrap_or_default()
.to_ascii_lowercase();
let mime = match extension.as_str() {
"mp3" => "audio/mpeg",
"wav" => "audio/wav",
other => {
anyhow::bail!("unsupported voice clone sample extension '{other}'. Use .mp3 or .wav.");
}
};
Ok(format!("data:{mime};base64,{base64_audio}"))
}
pub(crate) fn describe_speech_voice(voice: &str) -> String {
if voice.starts_with("data:") {
"embedded voice clone sample".to_string()
} else {
voice.to_string()
}
}
fn openai_compatible_base_url(base_url: &str) -> String {
let trimmed = base_url.trim_end_matches('/');
if trimmed.ends_with("/v1") || trimmed.ends_with("/beta") {
trimmed.to_string()View on GitHub (pinned to 0c42157ee5)
Solutions
- Convert the sample to mp3 or wav before uploading: ffmpeg -i in.m4a -codec:a libmp3lame -b:a 128k sample.mp3.
- If the content is already mp3/wav with a wrong suffix, rename the file so the extension matches the actual container.
- Ensure tempfile-based flows preserve a .mp3/.wav suffix instead of a random name.
Example fix
# before ffmpeg -i recording.m4a voice.wav # then pass voice.wav? no - pass original .m4a -> rejected # after ffmpeg -i recording.m4a -codec:a libmp3lame -b:a 128k voice.mp3 # pass voice.mp3 -> accepted
Defensive patterns
Strategy: type-guard
Validate before calling
fn sample_extension_supported(path: &Path) -> bool {
matches!(
path.extension().and_then(|e| e.to_str()).map(|e| e.to_ascii_lowercase()).as_deref(),
Some("mp3" | "wav")
)
} Type guard
fn is_supported_voice_sample(path: &Path) -> bool {
matches!(
path.extension().and_then(|e| e.to_str()).map(str::to_ascii_lowercase).as_deref(),
Some("mp3" | "wav")
)
} Prevention
- Convert phone/DAW recordings (m4a, flac, ogg) to mp3 or wav before using them as clone samples.
- Preserve the file extension when staging samples in temp dirs.
- The check is on the extension only, so make sure the container actually matches the suffix.
When it happens
Trigger: Passing .m4a, .ogg, .flac, .opus, .webm, uppercase variants are fine (lowercased) but .MP3 works while .mp4 fails; passing a file with no extension; passing a temporary file whose suffix was stripped.
Common situations: iPhone/Android recordings (.m4a, .amr); Audacity exports as .flac or .ogg; voice memos renamed without extension; tempfiles created without suffix.
Related errors
- voice clone sample is too large after base64 encoding ({} by
- speech synthesis requires provider 'xiaomi-mimo' (current: {
- Model '{model}' requires cloned voice data. Pass --clone-voi
- ${name} is unavailable in Workflow scripts: runs must be det
- new Date()/Date() is unavailable in Workflow scripts: runs m
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/9b9c16dd85ebc575.
Report an issue: GitHub.