SubtitleEdit/subtitleedit · error · OcrException
API key invalid (or perhaps billing/API is not enabled)?
Error message
API key invalid (or perhaps billing/API is not enabled)?
What it means
OcrException thrown when the Google Cloud Vision REST call returns HTTP 400. 400 from the Vision API specifically means the request was malformed or the API key was rejected as invalid — billing/quota issues surface as 403 instead (see the next guard). The body is not inspected; only the status code drives the message.
Source
Thrown at src/libuilogic/Ocr/Service/GoogleCloudVisionApi.cs:204
}
// Convert to JSON string
string requestBodyString;
using (var memoryStream = new MemoryStream())
{
new DataContractJsonSerializer(typeof(RequestBody)).WriteObject(memoryStream, requestBody);
requestBodyString = Encoding.Default.GetString(memoryStream.ToArray());
}
// Do request
var uri = $"?key={_apiKey}";
string content;
try
{
var result = _httpClient.PostAsync(uri, new StringContent(requestBodyString)).Result;
if ((int)result.StatusCode == 400)
{
throw new OcrException("API key invalid (or perhaps billing/API is not enabled)?");
}
if ((int)result.StatusCode == 403)
{
throw new OcrException("\"Perhaps billing is not enabled (or API not enabled or API key is invalid)?\"");
}
if (!result.IsSuccessStatusCode)
{
throw new OcrException($"An error occurred calling Cloud Vision API - status code: {result.StatusCode}");
}
content = result.Content.ReadAsStringAsync().Result;
}
catch (WebException webException)
{
var message = string.Empty;
if (webException.Message.Contains("(400) Bad Request"))View on GitHub (pinned to 17a9f07487)
Solutions
- Open GCP > APIs & Services > Credentials and confirm the API key still exists and is unrestricted for Vision.
- Regenerate the key and re-enter it without surrounding spaces or quotes.
- Make sure you are passing an API key (starts with AIza...) and not an OAuth token or service-account private key.
- Re-run with the same body using curl and the same key to see Google's detailed error JSON.
Example fix
// before
if ((int)result.StatusCode == 400)
throw new OcrException("API key invalid (or perhaps billing/API is not enabled)?");
// after — surface Google's reason from the body so 400 (bad request) is distinguishable from auth
if ((int)result.StatusCode == 400)
{
var body = result.Content.ReadAsStringAsync().Result;
throw new OcrException($"Cloud Vision API rejected the request (400). Body: {body}");
} Defensive patterns
Strategy: validation
Validate before calling
static void ValidateApiKey(string key)
{
if (string.IsNullOrWhiteSpace(key)) throw new OcrException("Cloud Vision API key is empty.");
if (!key.StartsWith("AIza", StringComparison.Ordinal) || key.Length != 39) throw new OcrException("Key does not look like a Google API key (AIza..., 39 chars).");
} Type guard
null
Try / catch
try { content = CallVision(...); }
catch (OcrException ex) when (ex.Message.Contains("API key invalid")) { SeLogger.Error("Vision key rejected; verify GCP Credentials."); throw; } Prevention
- Trim the API key on input to kill trailing whitespace.
- Validate the AIza prefix + length at config-save time, not just at call time.
- Do a 1-image smoke test after entering a key to fail fast.
When it happens
Trigger: Posting to the Vision API with a missing, mistyped, revoked, or wrong-format _apiKey; or with a malformed request body the API rejects pre-auth.
Common situations: Pasted key with trailing whitespace; copied a service-account JSON instead of an API key; key deleted in GCP Console; environment mismatch (dev key in prod); typo in the key.
Related errors
- API key invalid (or perhaps billing/API is not enabled)?
- "Perhaps billing is not enabled (or API not enabled or API k
- An error occurred calling Cloud Vision API - status code: {r
- {error}
- BinaryOCR database not found: {dbPath}. Use --ocr-db to poin
AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13).
Data as JSON: /api/errors/a48760395f8e0e6e.
Report an issue: GitHub.