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

Thrown by GoogleVisionOcr.Ocr for any non-success HTTP status that is not 400 or 403 — the catch-all branch after the two specific checks. The status code is interpolated into the message.

Source

Thrown at src/ui/Features/Ocr/Engines/GoogleVisionOcr.cs:200

        // Do request
        var uri = $"?key={apiKey}";
        string content;
        try
        {
            var result = await _httpClient.PostAsync(uri, new StringContent(requestBodyString), cancellationToken);
            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 = await result.Content.ReadAsStringAsync(cancellationToken);
        }
        catch (HttpRequestException httpException)
        {
            throw new OcrException("Error calling Cloud Vision API: " + httpException.Message, httpException);
        }

        return string.Join(Environment.NewLine, JsonToStringList(language, content));
    }

    public static List<string> JsonToStringList(string language, string content)
    {
        if (Configuration.Settings.Tools.OcrGoogleCloudVisionSeHandlesTextMerge)
        {
            var annotations = GetAnnotations(content).ToList();
            if (annotations.Count > 0)

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Read result.StatusCode from the message and react: 429 → back off / request quota increase; 5xx → retry with jitter; 404 → fix the base address.
  2. For rate limits, throttle calls and consider batching images per Vision request.
  3. Confirm the HttpClient's base address is the Vision annotate endpoint.
  4. Retry transient 5xx with exponential backoff.

Example fix

// retry on 5xx/429
var policy = Policy.Handle<OcrException>()
    .WaitAndRetryAsync(3, i => TimeSpan.FromSeconds(Math.Pow(2, i)));
await policy.ExecuteAsync(() => ocr.Ocr(bmp, key, lang, ct));
Defensive patterns

Strategy: retry

Validate before calling

null

Type guard

null

Try / catch

try { return await ocr.Ocr(bmp, key, lang, ct); }
catch (OcrException ex) when (ex.Message.Contains("429") || ex.Message.Contains("503")) {
    await Task.Delay(TimeSpan.FromSeconds(backoff), ct); return await ocr.Ocr(bmp, key, lang, ct); }

Prevention

When it happens

Trigger: result.IsSuccessStatusCode is false AND the status is neither 400 nor 403 (e.g. 401, 404, 429, 500, 503).

Common situations: 429 rate-limit/quota exceeded; 401 unauthorized (expired OAuth-style key); 5xx transient Google outage; 404 wrong endpoint base URL configured on the HttpClient.

Related errors


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