{"record":{"id":"50f29ad8dd99351c","repo":"SubtitleEdit/subtitleedit","slug":"staticname-failed-with-status-code-int-result","errorCode":null,"errorMessage":"{StaticName} failed with status code {(int)result.StatusCode} ({result.StatusCode}) - free API quota exceeded?\n\n {jsonResultString}","messagePattern":"(.+?) failed with status code (.+?) \\((.+?)\\) - free API quota exceeded\\?\n\n (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/libuilogic/AutoTranslate/GoogleTranslateV1.cs","lineNumber":66,"sourceCode":"\n        public async Task<string> Translate(string input, string sourceLanguageCode, string targetLanguageCode, CancellationToken cancellationToken)\n        {\n            string jsonResultString;\n\n            try\n            {\n                var text = input.Replace(\"\\r\", string.Empty).Trim();\n                var url = $\"translate_a/single?client=gtx&sl={sourceLanguageCode}&tl={targetLanguageCode}&dt=t&q={Utilities.UrlEncode(text)}\";\n\n                var result = await _httpClient.GetAsync(url, cancellationToken);\n                var bytes = await result.Content.ReadAsByteArrayAsync(cancellationToken);\n                jsonResultString = Encoding.UTF8.GetString(bytes).Trim();\n\n                if (!result.IsSuccessStatusCode)\n                {\n                    Error = jsonResultString;\n                    SeLogger.Error($\"Error in {StaticName}.Translate: \" + Error);\n                    throw new Exception($\"{StaticName} failed with status code {(int)result.StatusCode} ({result.StatusCode}) - free API quota exceeded?\" + Environment.NewLine + Environment.NewLine + jsonResultString);\n                }\n            }\n            catch (WebException webException)\n            {\n                throw new Exception(\"Free API quota exceeded?\", webException);\n            }\n\n            var resultList = ConvertJsonObjectToStringLines(jsonResultString);\n            return string.Join(Environment.NewLine, resultList);\n        }\n\n        public static List<TranslationPair> GetTranslationPairs()\n        {\n            return new List<TranslationPair>\n            {\n                new TranslationPair(\"AFAR\", \"aa\"),\n                new TranslationPair(\"AFRIKAANS\", \"af\"),\n                new TranslationPair(\"ALBANIAN\", \"sq\"),","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/libuilogic/AutoTranslate/GoogleTranslateV1.cs#L48-L84","documentation":"Thrown by GoogleTranslateV1 when the free, unofficial Google translate endpoint (translate.googleapis.com/translate_a/single with client=gtx) returns a non-success HTTP status. This endpoint is undocumented and rate-limited; Google throttles or blocks it aggressively, hence the 'free API quota exceeded?' guess in the message.","triggerScenarios":"Translate() builds a GET to translate_a/single?client=gtx&...&q=<encoded text>; the response status is not success. Most commonly HTTP 429 Too Many Requests, but also 403/503 when Google detects automated use, or 502 from a proxy.","commonSituations":"Bulk-translating many lines quickly triggers Google's per-IP throttle; behind a shared/NAT IP that other automated clients also hit; proxy or VPN IP already flagged; using a User-Agent that looks automated (the code sets a Chrome UA at line 34, which helps but is not bulletproof).","solutions":["Slow down: add delays between requests to stay under Google's per-IP rate limit.","Switch to GoogleTranslateV2 (official API with key) for reliable bulk translation.","Rotate off a flagged IP (disable VPN/proxy, or use a residential proxy).","Reduce batch sizes and retry after a cooldown."],"exampleFix":"// before\nthrow new Exception($\"{StaticName} failed with status code {(int)result.StatusCode} ({result.StatusCode}) - free API quota exceeded?\" + Environment.NewLine + Environment.NewLine + jsonResultString);\n\n// after - branch on 429 so callers can back off rather than treat it as fatal\nif ((int)result.StatusCode == 429)\n{\n    throw new Exception($\"{StaticName} rate-limited (429) by Google's free endpoint - slow down or use GoogleTranslateV2 with an API key.\");\n}\nthrow new Exception($\"{StaticName} failed with status code {(int)result.StatusCode} ({result.StatusCode}) - free API quota exceeded?\" + Environment.NewLine + Environment.NewLine + jsonResultString);","handlingStrategy":"retry","validationCode":"// Google's free endpoint throttles hard; enforce a client-side rate limit before calling\nprivate static readonly TimeSpan MinInterval = TimeSpan.FromMilliseconds(1200);\nprivate static DateTime _lastCall = DateTime.MinValue;\npublic async Task<string> TranslateThrottled(...)\n{\n    var wait = MinInterval - (DateTime.UtcNow - _lastCall);\n    if (wait > TimeSpan.Zero) await Task.Delay(wait, token);\n    try { return await v1.Translate(text, src, tgt, token); }\n    finally { _lastCall = DateTime.UtcNow; }\n}","typeGuard":null,"tryCatchPattern":"for (int attempt = 0; attempt < 4; attempt++)\n{\n    try { return await googleV1.Translate(text, src, tgt, token); }\n    catch (Exception ex) when (ex.Message.Contains(\"429\") || ex.Message.Contains(\"quota exceeded\"))\n    {\n        await Task.Delay(TimeSpan.FromSeconds(5 * (attempt + 1)), token);\n    }\n}\nthrow new InvalidOperationException(\"Google free endpoint kept rate-limiting after retries - use GoogleTranslateV2.\");","preventionTips":["Prefer GoogleTranslateV2 (official API) for any non-trivial volume.","Throttle GoogleTranslateV1 to <= ~1 request/second per IP.","Cache translations to avoid repeat hits to the free endpoint.","Detect 429 and back off with exponential delay; do not retry immediately."],"tags":["network","rate-limit","translation","google","unofficial-api"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}