{"record":{"id":"0221785068b5cbce","repo":"SubtitleEdit/subtitleedit","slug":"api-key-invalid-or-perhaps-billing-is-not-enabled","errorCode":null,"errorMessage":"API key invalid (or perhaps billing is not enabled)?","messagePattern":"API key invalid \\(or perhaps billing is not enabled\\)\\?","errorType":"exception","errorClass":"Exception","httpStatus":400,"severity":"error","filePath":"src/libuilogic/AutoTranslate/GoogleTranslateV2.cs","lineNumber":76,"sourceCode":"                var result = await _httpClient.PostAsync(uri, new StringContent(string.Empty), cancellationToken);\n\n                if (!result.IsSuccessStatusCode)\n                {\n                    try\n                    {\n                        Error = await result.Content.ReadAsStringAsync(cancellationToken);\n                        SeLogger.Error($\"Error in {StaticName}.Translate: \" + Error);\n                    }\n                    catch\n                    {\n\n                        // ignore\n                    }\n                }\n\n                if ((int)result.StatusCode == 400)\n                {\n                    throw new Exception(\"API key invalid (or perhaps billing is not enabled)?\");\n                }\n                if ((int)result.StatusCode == 403)\n                {\n                    throw new Exception(\"\\\"Perhaps billing is not enabled (or API key is invalid)?\\\"\");\n                }\n\n                if (!result.IsSuccessStatusCode)\n                {\n                    throw new Exception($\"An error occurred calling GT translate - status code: {result.StatusCode}\");\n                }\n\n                content = await result.Content.ReadAsStringAsync(cancellationToken);\n            }\n            catch (WebException webException)\n            {\n                var message = string.Empty;\n                if (webException.Message.Contains(\"(400) Bad Request\"))\n                {","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/libuilogic/AutoTranslate/GoogleTranslateV2.cs#L58-L94","documentation":"Thrown by GoogleTranslateV2 (official Google Cloud Translation API v2 with an API key) when the POST returns HTTP 400 Bad Request. Google returns 400 when the API key is malformed, missing, or when the key is valid but the Cloud Translation API is not enabled / billing is not active on the project.","triggerScenarios":"Translate() posts to https://translation.googleapis.com/language/translate/v2/?...&key=<key>; result.StatusCode is 400. Note the key is sent as a query parameter (line 54), so a malformed key lands here.","commonSituations":"Empty or whitespace API key (GoogleApiV2Key not set); key from a project where the Translation API is not enabled; billing disabled on the GCP project; key copied with extra characters; key restricted to an API/project that does not include Translation.","solutions":["Verify GoogleApiV2Key is set and non-empty in Settings.","In the GCP console, enable the Cloud Translation API for the key's project.","Confirm billing is enabled on the GCP project (Translation requires billing even for the free tier).","Check the API key restrictions allow the Translation API and the calling IP."],"exampleFix":"// before\nif ((int)result.StatusCode == 400)\n{\n    throw new Exception(\"API key invalid (or perhaps billing is not enabled)?\");\n}\n\n// after - read Google's JSON error to report the exact reason instead of guessing\nif ((int)result.StatusCode == 400)\n{\n    throw new Exception($\"GoogleTranslateV2 returned 400: {Error}\");\n}","handlingStrategy":"validation","validationCode":"// Validate the V2 key is present and looks like a Google API key before calling\nvar key = Configuration.Settings.Tools.GoogleApiV2Key;\nif (string.IsNullOrWhiteSpace(key))\n    throw new InvalidOperationException(\"Google Translate V2 API key is not set.\");\nif (key.Length < 30)\n    throw new InvalidOperationException(\"Google Translate V2 API key looks too short - verify it was copied fully.\");","typeGuard":"public static bool LooksLikeGoogleV2Key(string key)\n    => !string.IsNullOrWhiteSpace(key) && key.StartsWith(\"AIza\", StringComparison.Ordinal) && key.Length >= 35;","tryCatchPattern":"try\n{\n    return await googleV2.Translate(text, src, tgt, token);\n}\ncatch (Exception ex) when (ex.Message.Contains(\"API key invalid\"))\n{\n    throw new InvalidOperationException(\"Google returned 400 - the API key is invalid or the Translation API / billing is not enabled.\", ex);\n}","preventionTips":["Set GoogleApiV2Key before Initialize; fail fast in the UI if it is empty.","Enable the Cloud Translation API and billing on the GCP project before first use.","Use a key whose restrictions allow the Translation API and the caller IP.","Log only the key prefix (first 6 chars) to confirm the right key is loaded."],"tags":["api","auth","billing","translation","google","configuration"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}