zeroclaw-labs/zeroclaw · warning
Google STT requires a file extension
Error message
Google STT requires a file extension
What it means
GoogleSttProvider::transcribe() derives the encoding from the file extension; when file_name contains no '.' at all, the extension Option is None and the provider bails before any API call. This is the sibling of error 289: 289 is an unrecognized extension, 290 is no extension to recognize.
Source
Thrown at crates/zeroclaw-channels/src/transcription.rs:705
.map(String::from)
.collect()
}
async fn transcribe(&self, audio_data: &[u8], file_name: &str) -> Result<String> {
let (normalized_name, _) = validate_audio(audio_data, file_name)?;
let encoding = match normalized_name
.rsplit_once('.')
.map(|(_, e)| e.to_ascii_lowercase())
.as_deref()
{
Some("flac") => "FLAC",
Some("wav") => "LINEAR16",
Some("ogg" | "opus") => "OGG_OPUS",
Some("mp3") => "MP3",
Some("webm") => "WEBM_OPUS",
Some(ext) => bail!("Google STT does not support '.{ext}' input"),
None => bail!("Google STT requires a file extension"),
};
let audio_content =
base64::Engine::encode(&base64::engine::general_purpose::STANDARD, audio_data);
let request_body = serde_json::json!({
"config": {
"encoding": encoding,
"languageCode": &self.language_code,
"enableAutomaticPunctuation": true,
},
"audio": {
"content": audio_content,
}
});
let resp = self
.build_request(&request_body)?View on GitHub (pinned to 88bb9c8533)
Solutions
- Pass the real filename including extension into transcribe()
- If the original name is lost, derive an extension from the MIME type (e.g. audio/ogg -> .ogg) before calling
- Default unknown bare names to the extension that matches how you captured the audio (Telegram voice notes are .ogg)
Example fix
// before
let text = manager.transcribe(&audio, "voice_message").await?;
// after: derive a usable name from the Telegram MIME type
let name = extension_for_audio_mime(mime).map(|e| format!("voice.{e}"))
.unwrap_or_else(|| "voice.ogg".to_string());
let text = manager.transcribe(&audio, &name).await?; Defensive patterns
Strategy: validation
Validate before calling
fn has_audio_extension(file_name: &str) -> bool {
file_name.rsplit_once('.').is_some_and(|(_, e)| !e.is_empty())
} Type guard
fn has_audio_extension(file_name: &str) -> bool {
matches!(file_name.rsplit_once('.'), Some((_, e)) if !e.is_empty())
} Prevention
- Always pass the original upload filename through to transcribe()
- If names are synthesized, derive an extension from the MIME type or default to .ogg for Telegram voice notes
- Cover the no-extension case in channel tests with a bare-name fixture
When it happens
Trigger: transcribe() on the google provider with a file_name like "voice", "audio-2026-08-22", or "recording" — any string without a dot. The Google provider is the only one that hard-fails on a missing extension (Whisper-compatible providers fall back through their own normalization).
Common situations: Channel code synthesizing names from database IDs or timestamps instead of preserving the upload filename; stripping extensions in an upload pipeline; test fixtures named without extensions.
Related errors
- Google STT does not support '.{ext}' input
- Google STT API error ({}): {}
- Audio file too large ({} bytes, max {MAX_AUDIO_BYTES})
- Audio file too large ({} bytes, local_whisper max {})
- Audio file too large ({} bytes, global max {})
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/22c2833d330ac7ae.
Report an issue: GitHub.