{"record":{"id":"f1879c3eaaee9a4c","repo":"SubtitleEdit/subtitleedit","slug":"lens-returned-a-non-200-status-code","errorCode":null,"errorMessage":"Lens returned a non-200 status code","messagePattern":"Lens returned a non-200 status code","errorType":"exception","errorClass":"CoreError","httpStatus":null,"severity":"error","filePath":"src/ui/Logic/Ocr/GoogleLens/Core.cs","lineNumber":214,"sourceCode":"                saveConsentRequest.Headers.Add(kvp.Key, kvp.Value);\n            }\n\n            var saveConsentResponse = await _fetch(saveConsentRequest);\n\n            if (saveConsentResponse.StatusCode == System.Net.HttpStatusCode.SeeOther)\n            {\n                if (saveConsentResponse.Headers.TryGetValues(\"set-cookie\", out var consentCookies))\n                {\n                    SetCookies(consentCookies);\n                }\n                await Task.Delay(500);\n                return await FetchAsync(formdata, originalDimensions, true);\n            }\n        }\n\n        if (response.StatusCode != System.Net.HttpStatusCode.OK)\n        {\n            throw new CoreError(\"Lens returned a non-200 status code\", (int)response.StatusCode, response.Headers, text);\n        }\n\n        try\n        {\n            var afData = GetAFData(responseBody);\n            return ParseResult(afData!, originalDimensions);\n        }\n        catch (Exception e)\n        {\n            throw new CoreError($\"Could not parse response: {e.Message}\", (int)response.StatusCode, response.Headers, text);\n        }\n    }\n    \n    public async Task<List<string>> ScanByData(byte[] uint8, string mime, int[] originalDimensions)\n    {\n        if (!Constants.SUPPORTED_MIMES.Contains(mime))\n        {\n            throw new Exception(\"File type not supported\");","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/ui/Logic/Ocr/GoogleLens/Core.cs#L196-L232","documentation":"Thrown by Core.FetchAsync when, after exhausting the 302/consent handling, the final response status is anything other than 200 OK. Wrapped in CoreError with the numeric status, headers, and raw text so the caller can diagnose (e.g. 400 bad request, 429 rate limit, 500 server error, 403 blocked).","triggerScenarios":"Lens returns 429 (too many requests), 403 (blocked/forbidden), 400 (malformed multipart), 500/502/503 (server/edge fault), or any non-200/non-302 status after the consent flow completes.","commonSituations":"Rate limiting from too many OCR calls; Google blocking the User-Agent/IP; a malformed multipart body; upstream outage; expired/invalid cookies yielding 403.","solutions":["Inspect CoreError.StatusCode: back off on 429, switch engine on 403, fix payload on 400.","Exponential backoff + retry for 5xx and 429 responses.","Rotate User-Agent / proxy if 403 persists.","Refresh cookies by re-running the consent handshake from a clean session."],"exampleFix":"// before\nvar result = await core.FetchAsync(formdata, dims);\n\n// after\ntry { var result = await core.FetchAsync(formdata, dims); }\ncatch (CoreError ex) { if (ex.StatusCode == 429) await Task.Delay(5000); else throw; }","handlingStrategy":"retry","validationCode":"// Cannot prevent a server-side non-200, but you can pre-check connectivity:\nif (await HttpClientFactoryWithProxy.CreateHttpClientWithProxy().GetAsync(HeaderData.Config[\"endpoint\"].ToString()) is { } probe && !probe.IsSuccessStatusCode) { /* degrading */ }","typeGuard":null,"tryCatchPattern":"try { var r = await core.FetchAsync(formdata, dims); }\ncatch (CoreError ex)\n{\n    if (ex.StatusCode == 429) await Task.Delay(5000);\n    else if (ex.StatusCode >= 500) await Task.Delay(1000);\n    else throw;\n}","preventionTips":["Back off exponentially on 429/5xx.","Rotate User-Agent/proxy on 403.","Refresh cookies by re-running the consent handshake.","Validate the multipart payload shape before sending."],"tags":["google-lens","ocr","network","http","rate-limit","retry"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}