{"record":{"id":"ecb9086a2d9250c2","repo":"decolua/9router","slug":"google-tts-failed-res-status","errorCode":null,"errorMessage":"Google TTS failed: ${res.status}","messagePattern":"Google TTS failed: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"open-sse/handlers/ttsProviders/googleTts.js","lineNumber":47,"sourceCode":"    const reqId = (++_idx * 100000) + Math.floor(1000 + Math.random() * 9000);\n    const query = new URLSearchParams({\n      rpcids: rpcId,\n      \"f.sid\": token[\"f.sid\"],\n      bl: token.bl,\n      hl: lang,\n      \"soc-app\": 1, \"soc-platform\": 1, \"soc-device\": 1,\n      _reqid: reqId,\n      rt: \"c\",\n    });\n    const payload = [cleanText, lang, null, \"undefined\", [0]];\n    const body = new URLSearchParams();\n    body.append(\"f.req\", JSON.stringify([[[rpcId, JSON.stringify(payload), null, \"generic\"]]]));\n    const res = await fetch(`https://translate.google.com/_/TranslateWebserverUi/data/batchexecute?${query}`, {\n      method: \"POST\",\n      headers: { \"Content-Type\": \"application/x-www-form-urlencoded\", \"Referer\": \"https://translate.google.com/\" },\n      body: body.toString(),\n    });\n    if (!res.ok) throw new Error(`Google TTS failed: ${res.status}`);\n    const data = await res.text();\n    const split = JSON.parse(data.split(\"\\n\")[3]);\n    const base64 = JSON.parse(split[0][2])[0];\n    if (!base64 || base64.length < 100) throw new Error(\"Google TTS returned empty audio\");\n    return { base64, format: \"mp3\" };\n  },\n};\n","sourceCodeStart":29,"sourceCodeEnd":55,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/open-sse/handlers/ttsProviders/googleTts.js#L29-L55","documentation":"The synthesize function POSTs an RPC batchexecute request to translate.google.com to get MP3 audio. Non-2xx responses throw this error with the upstream HTTP status. Since this is an undocumented internal Google RPC endpoint, non-200s usually mean the request/token is stale or blocked.","triggerScenarios":"batchexecute returns 4xx/5xx: expired/invalid `f.sid`/`bl` token in the query, missing/bad Referer, rate limiting (429), or Google blocking the internal RPC for the client IP.","commonSituations":"Long-lived process using a token scraped hours ago that Google invalidated; datacenter IP blocked; malformed f.req after a payload schema change (surfacing as 400).","solutions":["Invalidate the token cache and refetch (fix the scraper/token) so batchexecute runs with fresh f.sid/bl","Confirm headers: `Content-Type: application/x-www-form-urlencoded` and `Referer: https://translate.google.com/` must be present","Check the status code in the message: 429 → backoff/IP rotation; 400 → inspect the f.req payload against current schema","Switch to an official TTS provider or maintained google-tts-api library for reliability"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"null","typeGuard":"null","tryCatchPattern":"try { return await googleTts.synthesize(text); } catch (e) { const m = e.message.match(/Google TTS failed: (\\d+)/); if (m && (m[1] === '429' || m[1].startsWith('5'))) { await sleep(expBackoff()); return retryOnce(); } throw e; }","preventionTips":["Keep Referer and Content-Type headers exactly as the internal RPC expects","Refresh f.sid/bl tokens when this fires instead of retrying with the same stale token","Chunk long text to stay within batchexecute limits"],"tags":["network","http","google","tts","upstream"],"backgroundTag":"http-429-rate-limit","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}