zeroclaw-labs/zeroclaw · warning

Google STT does not support '.{ext}' input

Error message

Google STT does not support '.{ext}' input

What it means

GoogleSttProvider::transcribe() maps the file extension to a Google Speech-to-Text encoding enum and only accepts flac, wav, ogg, opus, mp3, and webm. Any other extension bails before any API call. Note the gap versus the shared validate_audio(): formats like m4a/mp4/mpga pass the 25 MB/format gate (mime_for_audio accepts them for Whisper-compatible APIs) but Google's provider rejects them right after.

Source

Thrown at crates/zeroclaw-channels/src/transcription.rs:704

            .into_iter()
            .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

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Route m4a/mp4/mpga inputs to a provider that accepts them (groq, openai) — set the agent's transcription_provider accordingly
  2. Convert the audio before transcribing: ffmpeg -i in.m4a -ar 16000 -ac 1 out.flac
  3. Add a per-extension provider selection at the channel layer so Google only receives its supported formats

Example fix

// before: .m4a sent to google provider -> error
let text = manager.transcribe_with_provider(&audio, "memo.m4a", "google").await?;

// after: convert first
let flac = transcode_to_flac(&audio)?;
let text = manager.transcribe_with_provider(&flac, "memo.flac", "google").await?;
Defensive patterns

Strategy: validation

Validate before calling

const GOOGLE_STT_EXTS: &[&str] = &["flac", "wav", "ogg", "opus", "mp3", "webm"];

fn google_stt_accepts(file_name: &str) -> bool {
    file_name.rsplit_once('.').map(|(_, e)| e.to_ascii_lowercase())
        .is_some_and(|e| GOOGLE_STT_EXTS.contains(&e.as_str()))
}

Type guard

fn google_stt_accepts(file_name: &str) -> bool {
    let ext = file_name.rsplit_once('.')
        .map(|(_, e)| e.to_ascii_lowercase())
        .unwrap_or_default();
    matches!(ext.as_str(), "flac" | "wav" | "ogg" | "opus" | "mp3" | "webm")
}

Prevention

When it happens

Trigger: transcribe() on the google provider with a file_name whose extension is not flac/wav/ogg/opus/mp3/webm — most commonly .m4a (iPhone voice memos), .mp4, .mpga, or .aac. The error message names the exact rejected extension.

Common situations: iPhone/Android voice notes recorded as .m4a routed to the google provider while other formats work fine; switching a working Groq/OpenAI setup to Google and suddenly m4a inputs fail; users sending audio as video-less .mp4 containers.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/2b5c1f7f94840ae3. Report an issue: GitHub.