{"record":{"id":"6b91ff4e9a9333b1","repo":"SubtitleEdit/subtitleedit","slug":"free-api-quota-exceeded","errorCode":null,"errorMessage":"Free API quota exceeded?","messagePattern":"Free API quota exceeded\\?","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/libuilogic/AutoTranslate/GoogleTranslateV1.cs","lineNumber":71,"sourceCode":"            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\"),\n                new TranslationPair(\"AMHARIC\", \"am\"),\n                new TranslationPair(\"ARABIC\", \"ar\"),\n                new TranslationPair(\"ARMENIAN\", \"hy\"),\n                new TranslationPair(\"ASSAMESE\", \"as\"),\n                new TranslationPair(\"AYMARA\", \"ay\"),","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/libuilogic/AutoTranslate/GoogleTranslateV1.cs#L53-L89","documentation":"Thrown by GoogleTranslateV1 when a System.Net.WebException is caught during the free-endpoint GET (not an HTTP error status, which is handled at line 66). This is a transport-level failure: DNS, connection refused, TLS, or a protocol error from a proxy. The original WebException is preserved as the inner exception.","triggerScenarios":"The try at GoogleTranslateV1.cs:53 wraps the GET; any WebException (not HttpRequestException) escapes and is caught at line 69. Common with older .NET stacks where the underlying WebRequest surfaces transport errors as WebException rather than the newer HttpRequestException.","commonSituations":"No internet connection; DNS failure for translate.googleapis.com; corporate firewall/proxy blocking the host; TLS handshake failure on an outdated runtime; the gtx endpoint returning an HTML error page that the stack cannot parse as a clean HTTP response.","solutions":["Check basic connectivity: ping/curl https://translate.googleapis.com from the same machine.","Inspect the inner WebException status (ConnectFailure, NameResolutionFailure, etc.) for the root cause.","Configure proxy settings in SubtitleEdit if behind a corporate firewall.","Update the .NET runtime / OS TLS stack if the failure is protocol-related."],"exampleFix":"// before\ncatch (WebException webException)\n{\n    throw new Exception(\"Free API quota exceeded?\", webException);\n}\n\n// after - stop mislabeling transport errors as 'quota exceeded' and surface the real status\ncatch (WebException webException)\n{\n    var status = webException.Status;\n    if (status == WebExceptionStatus.Success || webException.Response != null)\n    {\n        throw new Exception(\"Free API quota exceeded?\", webException);\n    }\n    throw new Exception($\"GoogleTranslateV1 network error ({status}) reaching translate.googleapis.com.\", webException);\n}","handlingStrategy":"try-catch","validationCode":"// Pre-flight connectivity check to translate.googleapis.com\npublic static async Task<bool> CanReachGoogleFreeAsync(CancellationToken token)\n{\n    using var c = new HttpClient { Timeout = TimeSpan.FromSeconds(5) };\n    try { (await c.GetAsync(\"https://translate.googleapis.com\", token)).EnsureSuccessStatusCode(); return true; }\n    catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"try\n{\n    return await googleV1.Translate(text, src, tgt, token);\n}\ncatch (Exception ex) when (ex.InnerException is System.Net.WebException we && we.Response == null)\n{\n    // Transport error, not quota\n    throw new InvalidOperationException(\"Cannot reach translate.googleapis.com - check network/proxy.\", ex);\n}\ncatch (Exception ex) when (ex.Message.Contains(\"quota exceeded\"))\n{\n    // Likely a rate-limit/quota block\n    throw new InvalidOperationException(\"Google free endpoint rate-limited the request.\", ex);\n}","preventionTips":["Inspect the WebException.Status to distinguish transport errors from quota blocks.","Configure proxy settings for environments behind a corporate firewall.","Do not treat every WebException as 'quota exceeded' - the message is misleading for transport failures.","Keep the .NET runtime patched so TLS/SNI issues do not surface as WebException."],"tags":["network","transport","translation","google"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}