{"record":{"id":"a188fc580679602a","repo":"SubtitleEdit/subtitleedit","slug":"an-error-occurred-calling-cloud-vision-api-statu","errorCode":null,"errorMessage":"An error occurred calling Cloud Vision API - status code: {result.StatusCode}","messagePattern":"An error occurred calling Cloud Vision API - status code: (.+?)","errorType":"exception","errorClass":"OcrException","httpStatus":null,"severity":"error","filePath":"src/libuilogic/Ocr/Service/GoogleCloudVisionApi.cs","lineNumber":214,"sourceCode":"            // Do request\n            var uri = $\"?key={_apiKey}\";\n            string content;\n            try\n            {\n                var result = _httpClient.PostAsync(uri, new StringContent(requestBodyString)).Result;\n                if ((int)result.StatusCode == 400)\n                {\n                    throw new OcrException(\"API key invalid (or perhaps billing/API is not enabled)?\");\n                }\n\n                if ((int)result.StatusCode == 403)\n                {\n                    throw new OcrException(\"\\\"Perhaps billing is not enabled (or API not enabled or API key is invalid)?\\\"\");\n                }\n\n                if (!result.IsSuccessStatusCode)\n                {\n                    throw new OcrException($\"An error occurred calling Cloud Vision API - status code: {result.StatusCode}\");\n                }\n\n                content = result.Content.ReadAsStringAsync().Result;\n            }\n            catch (WebException webException)\n            {\n                var message = string.Empty;\n                if (webException.Message.Contains(\"(400) Bad Request\"))\n                {\n                    message = \"API key invalid (or perhaps billing is not enabled)?\";\n                }\n                else if (webException.Message.Contains(\"(403) Forbidden.\"))\n                {\n                    message = \"Perhaps billing is not enabled (or API key is invalid)?\";\n                }\n                throw new OcrException(message, webException);\n            }\n","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/libuilogic/Ocr/Service/GoogleCloudVisionApi.cs#L196-L232","documentation":"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.","triggerScenarios":"Hitting Vision API during an outage (5xx), exceeding per-minute request quotas (429), network blips (504), or a transient backend error.","commonSituations":"Batch OCR of many images hitting the 1800 req/min default quota; Google regional outage; slow upload on large images causing gateway timeouts.","solutions":["On 429, throttle to stay under your per-minute quota and retry with exponential backoff.","On 5xx/504, retry with backoff (these are transient); Vision API SLA covers most such cases.","Log result.Content so the next time you have Google's structured error reason instead of just a status code.","For batch work, add jitter and cap concurrency to avoid synchronized bursts."],"exampleFix":"// before\nif (!result.IsSuccessStatusCode)\n    throw new OcrException($\"An error occurred calling Cloud Vision API - status code: {result.StatusCode}\");\n\n// after\nif (!result.IsSuccessStatusCode)\n{\n    var body = result.Content.ReadAsStringAsync().Result;\n    throw new OcrException($\"Cloud Vision API {(int)result.StatusCode} {result.StatusCode}. Body: {body}\");\n}","handlingStrategy":"retry","validationCode":"null","typeGuard":"null","tryCatchPattern":"async Task<string> CallVisionWithRetry(...)\n{\n    for (int attempt = 0; attempt < 4; attempt++)\n    {\n        try { return await CallVision(...); }\n        catch (OcrException ex) when (IsTransient(ex))\n        {\n            await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt)));\n        }\n    }\n    throw new OcrException(\"Vision API failed after retries.\");\n}","preventionTips":["Implement exponential backoff with jitter for 429/5xx.","Log the response body, not just the status code — Vision returns structured error reasons.","Throttle concurrency to stay under your per-minute quota during batch OCR."],"tags":["ocr","google-cloud-vision","http","transient","rate-limit"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}