{"record":{"id":"6855413ad8df0fb0","repo":"decolua/9router","slug":"google-translate-fetch-failed-res-status","errorCode":null,"errorMessage":"Google translate fetch failed: ${res.status}","messagePattern":"Google translate fetch failed: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"open-sse/handlers/ttsProviders/googleTts.js","lineNumber":12,"sourceCode":"// Google Translate TTS (no auth) — scrape token + batchexecute RPC\nimport { UA } from \"./_base.js\";\n\nconst REFRESH_MS = 11 * 60 * 1000;\nconst cache = { token: null, tokenTime: 0 };\nlet _idx = 0;\n\nasync function getToken() {\n  const now = Date.now();\n  if (cache.token && now - cache.tokenTime < REFRESH_MS) return cache.token;\n  const res = await fetch(\"https://translate.google.com/\", { headers: { \"User-Agent\": UA } });\n  if (!res.ok) throw new Error(`Google translate fetch failed: ${res.status}`);\n  const html = await res.text();\n  const fSid = html.match(/\"FdrFJe\":\"(.*?)\"/)?.[1];\n  const bl = html.match(/\"cfb2h\":\"(.*?)\"/)?.[1];\n  if (!fSid || !bl) throw new Error(\"Failed to parse Google token\");\n  cache.token = { \"f.sid\": fSid, bl };\n  cache.tokenTime = now;\n  return cache.token;\n}\n\nexport default {\n  noAuth: true,\n  async synthesize(text, model) {\n    const lang = model || \"en\";\n    const token = await getToken();\n    const cleanText = text.replace(/[@^*()\\\\/\\-_+=><\"'\\u201c\\u201d\\u3010\\u3011]/g, \" \").replaceAll(\", \", \". \");\n    const rpcId = \"jQ1olc\";\n    const reqId = (++_idx * 100000) + Math.floor(1000 + Math.random() * 9000);\n    const query = new URLSearchParams({","sourceCodeStart":1,"sourceCodeEnd":30,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/open-sse/handlers/ttsProviders/googleTts.js#L1-L30","documentation":"The Google Translate (unofficial) TTS token scraper fetches https://translate.google.com/ to extract session params (`f.sid`, `bl`) from the page HTML. It throws this when the page fetch returns a non-2xx HTTP status. The token is cached and refreshed every REFRESH_MS, so this occurs on cold start and cache expiry.","triggerScenarios":"The GET to translate.google.com returns 4xx/5xx — e.g. 429 from rate limiting the scraper, 503 from regional blocking, or network/proxy interception returning an error status.","commonSituations":"Datacenter IPs being rate-limited or blocked by Google; no proper cookies/consent in a region requiring consent; corporate proxy returning error pages; Google deploying bot defenses against the translate page.","solutions":["Check the captured `res.status` in the message to identify the HTTP cause (429 = rate limited, 403 = blocked)","Retry after backoff — the cache means transient blocks self-heal once REFRESH_MS passes or a retry succeeds","Run from a residential/different IP or add proxy support; avoid hammering the endpoint","Consider an official TTS provider (or a maintained google-tts-api library) since this unofficial scraping path is inherently fragile"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"null","typeGuard":"null","tryCatchPattern":"try { await googleTts(text); } catch (e) { if (e.message.startsWith('Google translate fetch failed')) { const code = parseInt(e.message.match(/(\\d+)$/)?.[1]); if (code === 429 || code >= 500) await sleep(backoff); else throw e; } }","preventionTips":["Respect REFRESH_MS caching; don't force token refreshes in a loop","Run from IPs Google tolerates (avoid abused datacenter ranges)","Monitor and alert on repeated token-fetch failures; switch to an official API for production"],"tags":["network","http","google","scraping","rate-limit"],"backgroundTag":"http-429-rate-limit","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}