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

  1. Open GCP > APIs & Services > Credentials and confirm the API key still exists and is unrestricted for Vision.
  2. Regenerate the key and re-enter it without surrounding spaces or quotes.
  3. Make sure you are passing an API key (starts with AIza...) and not an OAuth token or service-account private key.
  4. 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

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


AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13). Data as JSON: /api/errors/a48760395f8e0e6e. Report an issue: GitHub.