zeroclaw-labs/zeroclaw · error
Google TTS API error ({}): {}
Error message
Google TTS API error ({}): {} What it means
Raised by GoogleTtsProvider::synthesize when POST https://texttospeech.googleapis.com/v1/text:synthesize returns non-2xx. The key travels in the x-goog-api-key header from [providers.tts.google.<alias>].api_key. Note the body is parsed as JSON first (a non-JSON body fails earlier with "Failed to parse Google TTS response"), then error.message is extracted, so this message means Google answered with a structured API error.
Source
Thrown at crates/zeroclaw-channels/src/tts.rs:368
.client
.post(url)
.header("x-goog-api-key", &self.api_key)
.json(&body)
.send()
.await
.context("Failed to send Google TTS request")?;
let status = resp.status();
let resp_body: serde_json::Value = resp
.json()
.await
.context("Failed to parse Google TTS response")?;
if !status.is_success() {
let msg = resp_body["error"]["message"]
.as_str()
.unwrap_or("unknown error");
bail!("Google TTS API error ({}): {}", status, msg);
}
let audio_b64 = resp_body["audioContent"]
.as_str()
.context("Google TTS response missing 'audioContent' field")?;
use base64::Engine;
let bytes = base64::engine::general_purpose::STANDARD
.decode(audio_b64)
.context("Failed to decode Google TTS base64 audio")?;
Ok(bytes)
}
fn supported_voices(&self) -> Vec<String> {
// Google voices vary by language; return common English defaults.
[
"en-US-Standard-A",
"en-US-Standard-B",View on GitHub (pinned to 88bb9c8533)
Solutions
- For 403 SERVICE_DISABLED, enable "Cloud Text-to-Speech API" in the GCP console for the key's project and enable billing.
- For 403 API_KEY_INVALID, fix [providers.tts.google.<alias>].api_key (env grammar ZEROCLAW_providers__tts__google__<alias>__api_key).
- For 400 voice/language messages, make voice and language_code agree, e.g. language_code = "en-US" with voice = "en-US-Standard-A", or switch to the en-GB voice set.
- For quota messages, raise the quota or back off; the built-in client already caps calls at 60s.
Example fix
# before — voice language does not match language_code [providers.tts.google.main] api_key = "AIza..." language_code = "en-US" voice = "en-GB-Standard-A" # after [providers.tts.google.main] api_key = "AIza..." language_code = "en-US" voice = "en-US-Standard-A"
Defensive patterns
Strategy: retry
Validate before calling
// Pre-flight: voice name must match its language prefix.
fn voice_matches_language(voice: &str, language_code: &str) -> bool {
// voice names look like "en-US-Standard-A" / "en-US-Neural2-F"
let prefix: String = language_code.chars().take_while(|c| c.is_ascii_alphanumeric() || *c == '-').collect();
voice.starts_with(&prefix)
}
assert!(voice_matches_language(voice, "en-US")); Try / catch
match mgr.synthesize(text).await {
Ok(audio) => Ok(audio),
Err(err) if err.to_string().contains("Google TTS API error (403)") => {
Err(err.context("enable Cloud Text-to-Speech API / check api_key"))
}
Err(err) if err.to_string().contains("(429)") => {
tokio::time::sleep(Duration::from_secs(2)).await;
mgr.synthesize(text).await
}
Err(err) => Err(err),
} Prevention
- Enable the Cloud Text-to-Speech API and billing on the key's project before deploying.
- Keep voice prefixes consistent with language_code in config review (en-US voice with en-US code).
- Restrict the API key to the Text-to-Speech API in the GCP console to avoid cross-service confusion.
When it happens
Trigger: 403 with API_KEY_INVALID or SERVICE_DISABLED (Cloud Text-to-Speech API not enabled on the project), 400 when the voice name does not match language_code (default en-US, e.g. voice en-GB-Standard-A with en-US), 400 for a malformed language_code, and 429/403 for quota or billing not enabled.
Common situations: The key exists but the Text-to-Speech API was never enabled in the GCP console. Copying a voice name from another language's docs while language_code stays en-US. Using a browser-API key restricted to different services.
Related errors
- ElevenLabs TTS API error ({}): {}
- OpenAI TTS API error ({}): {}
- Failed to initiate call: {}
- Piper TTS API error ({}): {}
- Twitter users/me failed ({status}): {err}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/cd02d5de2f6e81ed.
Report an issue: GitHub.