SubtitleEdit/subtitleedit · error · Exception
API key invalid (or perhaps API/billing is not enabled)?
Error message
API key invalid (or perhaps API/billing is not enabled)?
What it means
Thrown inside GoogleTranslateV2's catch (WebException) block when the exception message contains '(400) Bad Request'. This path is hit when the underlying transport (WebRequest-era stack) wraps a 400 response as a WebException rather than surfacing it as an HttpResponseMessage. The message maps 400 to an API-key/billing diagnosis. Note: if the WebException message matches neither branch, 'message' stays empty and the throw loses text (though the inner exception is preserved).
Source
Thrown at src/libuilogic/AutoTranslate/GoogleTranslateV2.cs:102
{
throw new Exception($"An error occurred calling GT translate - status code: {result.StatusCode}");
}
content = await result.Content.ReadAsStringAsync(cancellationToken);
}
catch (WebException webException)
{
var message = string.Empty;
if (webException.Message.Contains("(400) Bad Request"))
{
message = "API key invalid (or perhaps API/billing is not enabled)?";
}
else if (webException.Message.Contains("(403) Forbidden."))
{
message = "Perhaps billing is not enabled (or API not enabled or API key is invalid)?";
}
throw new Exception(message, webException);
}
var resultList = new List<string>();
var parser = new JsonParser();
var x = (Dictionary<string, object>)parser.Parse(content);
foreach (var k in x.Keys)
{
if (x[k] is Dictionary<string, object> v)
{
foreach (var innerKey in v.Keys)
{
if (v[innerKey] is List<object> l)
{
foreach (var o2 in l)
{
if (o2 is Dictionary<string, object> v2)
{
foreach (var innerKey2 in v2.Keys)View on GitHub (pinned to 17a9f07487)
Solutions
- Same as error 47: verify the API key, enable the Translation API, and enable billing.
- Inspect the inner WebException Response for Google's JSON error detail.
- Set GoogleApiV2Key before calling Initialize/Translate.
Example fix
// before
if (webException.Message.Contains("(400) Bad Request"))
{
message = "API key invalid (or perhaps API/billing is not enabled)?";
}
...
throw new Exception(message, webException);
// after - guarantee a non-empty message even when neither branch matches
var message = $"GoogleTranslateV2 transport error: {webException.Status}";
if (webException.Message.Contains("(400) Bad Request"))
{
message = "API key invalid (or perhaps API/billing is not enabled)?";
}
else if (webException.Message.Contains("(403) Forbidden."))
{
message = "Perhaps billing is not enabled (or API not enabled or API key is invalid)?";
}
throw new Exception(message, webException); Defensive patterns
Strategy: try-catch
Validate before calling
// Validate key presence before calling (the 400 transport path is just another symptom of a bad key)
var key = Configuration.Settings.Tools.GoogleApiV2Key;
if (string.IsNullOrWhiteSpace(key))
throw new InvalidOperationException("Google V2 API key is not set - a 400 will follow."); Try / catch
try
{
return await googleV2.Translate(text, src, tgt, token);
}
catch (Exception ex) when (ex.InnerException is WebException we && we.Message.Contains("(400) Bad Request"))
{
throw new InvalidOperationException("Google rejected the request (400) - invalid key or API/billing not enabled.", ex);
}
catch (Exception ex) when (string.IsNullOrWhiteSpace(ex.Message) && ex.InnerException is WebException)
{
// Guard against the empty-message pitfall: always surface something
throw new InvalidOperationException($"GoogleTranslateV2 transport error: {((WebException)ex.InnerException).Status}", ex);
} Prevention
- Validate the key is set and looks well-formed before the first call.
- When catching WebException, always inspect Status and Response rather than string-matching the message.
- Ensure a non-empty message is thrown even when neither string branch matches (current code can throw an empty message).
- Enable the Translation API + billing so 400s do not occur.
When it happens
Trigger: A WebException escapes the try at GoogleTranslateV2.cs:56; its Message contains '(400) Bad Request'. Same root cause as error 47 (invalid key / billing / API not enabled) but reached via the legacy exception path.
Common situations: Running on a runtime/config where the 400 is thrown as WebException instead of being delivered as a response; empty key; key for a project without the Translation API or billing enabled.
Related errors
- Perhaps billing is not enabled (or API not enabled or API ke
- API key invalid (or perhaps billing is not enabled)?
- "Perhaps billing is not enabled (or API key is invalid)?"
- Forbidden! {resultContent}
- Free API quota exceeded?
AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13).
Data as JSON: /api/errors/27c7652a067d4d88.
Report an issue: GitHub.