SubtitleEdit/subtitleedit · error · OcrException

An error occurred calling Cloud Vision API - status code: {r

Error message

An error occurred calling Cloud Vision API - status code: {result.StatusCode}

What it means

OcrException catch-all for any non-success status from the Cloud Vision call that is not 400 or 403 — typically 429 (rate limit), 500/502/503 (server-side), 408/504 (timeout), or 401. Only the StatusCode is included; the response body is discarded, so the real reason must be inferred from the code.

Source

Thrown at src/libuilogic/Ocr/Service/GoogleCloudVisionApi.cs:214

            // 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"))
                {
                    message = "API key invalid (or perhaps billing is not enabled)?";
                }
                else if (webException.Message.Contains("(403) Forbidden."))
                {
                    message = "Perhaps billing is not enabled (or API key is invalid)?";
                }
                throw new OcrException(message, webException);
            }

View on GitHub (pinned to 17a9f07487)

Solutions

  1. On 429, throttle to stay under your per-minute quota and retry with exponential backoff.
  2. On 5xx/504, retry with backoff (these are transient); Vision API SLA covers most such cases.
  3. Log result.Content so the next time you have Google's structured error reason instead of just a status code.
  4. For batch work, add jitter and cap concurrency to avoid synchronized bursts.

Example fix

// before
if (!result.IsSuccessStatusCode)
    throw new OcrException($"An error occurred calling Cloud Vision API - status code: {result.StatusCode}");

// after
if (!result.IsSuccessStatusCode)
{
    var body = result.Content.ReadAsStringAsync().Result;
    throw new OcrException($"Cloud Vision API {(int)result.StatusCode} {result.StatusCode}. Body: {body}");
}
Defensive patterns

Strategy: retry

Validate before calling

null

Type guard

null

Try / catch

async Task<string> CallVisionWithRetry(...)
{
    for (int attempt = 0; attempt < 4; attempt++)
    {
        try { return await CallVision(...); }
        catch (OcrException ex) when (IsTransient(ex))
        {
            await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt)));
        }
    }
    throw new OcrException("Vision API failed after retries.");
}

Prevention

When it happens

Trigger: Hitting Vision API during an outage (5xx), exceeding per-minute request quotas (429), network blips (504), or a transient backend error.

Common situations: Batch OCR of many images hitting the 1800 req/min default quota; Google regional outage; slow upload on large images causing gateway timeouts.

Related errors


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