zeroclaw-labs/zeroclaw · error
Google STT API error ({}): {}
Error message
Google STT API error ({}): {} What it means
GoogleSttProvider::transcribe() POSTs base64 audio to speech.googleapis.com/v1/speech:recognize and bails on non-2xx, embedding the status plus the body's error.message. The provider uses the synchronous v1 recognize endpoint, which has hard limits (roughly one minute / ~10 MB of audio per request), so long audio fails here even when the format is supported. The key is sent via the x-goog-api-key header.
Source
Thrown at crates/zeroclaw-channels/src/transcription.rs:736
"content": audio_content,
}
});
let resp = self
.build_request(&request_body)?
.send()
.await
.context("Failed to send transcription request to Google STT")?;
let status = resp.status();
let body: serde_json::Value = resp
.json()
.await
.context("Failed to parse Google STT response")?;
if !status.is_success() {
let error_msg = body["error"]["message"].as_str().unwrap_or("unknown error");
bail!("Google STT API error ({}): {}", status, error_msg);
}
let text = body["results"][0]["alternatives"][0]["transcript"]
.as_str()
.unwrap_or("")
.to_string();
Ok(text)
}
}
// ── LocalWhisperProvider ────────────────────────────────────────
pub struct LocalWhisperProvider {
alias: String,
url: String,
bearer_token: Option<String>,
max_audio_bytes: usize,View on GitHub (pinned to 88bb9c8533)
Solutions
- 400 with 'Sync input too long' — split audio into sub-minute chunks or switch to a provider that accepts long files (deepgram, assemblyai)
- 401/403 — check the api_key in [transcription.google] and remove API restrictions that block the Speech-to-Text API
- Verify the extension matches the real codec — the encoding enum is chosen purely from the file extension
- 429 — check Cloud Console quota for the Speech-to-Text API and retry with backoff
Example fix
# before: 5-minute voice note -> google provider -> 400 Sync input too long # after: split into <60s chunks ffmpeg -i note.ogg -f segment -segment_time 55 -ar 16000 -ac 1 -c:a flac chunk_%02d.flac # then transcribe chunks and join the texts
Defensive patterns
Strategy: try-catch
Validate before calling
// Google v1 speech:recognize is synchronous: cap audio at ~1 minute.
// Split or pick another provider before calling for longer input.
fn google_sync_recognize_ok(duration_secs: f64, bytes: usize) -> bool {
duration_secs <= 55.0 && bytes <= 10 * 1024 * 1024
} Try / catch
match provider.transcribe(&audio, name).await {
Ok(text) => Ok(text),
Err(e) => {
let msg = e.to_string();
if msg.contains("Sync input too long") {
Err(anyhow!("audio too long for google sync recognize; split it or use deepgram/assemblyai"))
} else if msg.contains("403") {
Err(anyhow!("google api key invalid or restricted for speech-to-text"))
} else {
Err(e)
}
}
} Prevention
- Keep Google-provider inputs under ~1 minute / 10 MB — the sync v1 endpoint has hard limits
- In Cloud Console, restrict the API key only to the Speech-to-Text API, not by IP/referrer unless the runtime egress matches
- Ensure the file extension matches the real codec — the encoding is inferred from the name
When it happens
Trigger: POST speech:recognize returns non-success: 400 'Sync input too long' for audio over ~1 minute, encoding/extension mismatch (declared FLAC but bytes are MP3), or invalid request shape; 403 API key invalid or restricted (HTTP-referrer/IP restrictions on the key); 429 quota exceeded.
Common situations: Long voice notes (>1 min) sent to the google provider — by far the most common hit; Google Cloud API key with restrictions that exclude the speech endpoint; wrong [transcription.google] api_key; declared encoding not matching actual bytes after a transcoding bug.
Related errors
- Deepgram API error ({}): {}
- Google STT does not support '.{ext}' input
- Google STT requires a file extension
- AssemblyAI upload error ({}): {}
- AssemblyAI transcription error ({}): {}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/5b63b34fc0510e85.
Report an issue: GitHub.