{"record":{"id":"7266d00bec658dac","repo":"SubtitleEdit/subtitleedit","slug":"lens-returned-status-code-int-response-statuscod","errorCode":null,"errorMessage":"Lens returned status code {(int)response.StatusCode}","messagePattern":"Lens returned status code (.+?)","errorType":"http","errorClass":"LensError","httpStatus":null,"severity":"error","filePath":"src/ui/Logic/Ocr/GoogleLens/LensCore.cs","lineNumber":332,"sourceCode":"        foreach (var kvp in headers)\n        {\n            if (kvp.Key.ToLower() != \"content-type\")\n            {\n                request.Headers.TryAddWithoutValidation(kvp.Key, kvp.Value);\n            }\n        }\n\n        var response = await _fetch!(request);\n\n        if (response.Headers.TryGetValues(\"set-cookie\", out var cookies))\n        {\n            SetCookies(cookies);\n        }\n\n        if (!response.IsSuccessStatusCode)\n        {\n            var errorBody = await response.Content.ReadAsStringAsync();\n            throw new LensError($\"Lens returned status code {(int)response.StatusCode}\", (int)response.StatusCode, response.Headers, errorBody);\n        }\n\n        var responseBytes = await response.Content.ReadAsByteArrayAsync();\n        return LensProtoResponse.Deserialize(responseBytes);\n    }\n\n    public async Task<LensResult> ScanByData(byte[] uint8Array, string mime, int[] originalDimensions, string twoLetterLanguageCode)\n    {\n        if (!Constants.SUPPORTED_MIMES.Contains(mime) && mime != \"image/gif\")\n        {\n            Console.WriteLine($\"MIME type {mime} might not be directly supported by the proto API, conversion recommended.\");\n        }\n\n        var actualDimensions = Helper.ImageDimensionsFromData(uint8Array);\n\n        var serializedRequest = CreateLensProtoRequest(uint8Array, actualDimensions.Width, actualDimensions.Height);\n        var serverResponse = await SendProtoRequest(serializedRequest, twoLetterLanguageCode);\n","sourceCodeStart":314,"sourceCodeEnd":350,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/ui/Logic/Ocr/GoogleLens/LensCore.cs#L314-L350","documentation":"A custom LensError thrown when the reverse-engineered Google Lens HTTP endpoint answers with a non-2xx status. It carries the numeric status code, response headers, and the body so callers can branch on 429 (rate limit), 4xx, or redirect/CAPTCHA challenges. Because this is an unofficial scrape of Lens, Google can change or break it at any time.","triggerScenarios":"_fetch returns a response with !IsSuccessStatusCode. Typical statuses: 401/403 (stale or missing cookies), 429 (rate limiting), 3xx or 200-with-HTML (CAPTCHA/consent redirect), 400/404 (Google changed the endpoint or rejected the protobuf payload), 5xx (transient Google outage).","commonSituations":"First run without warming cookies, batch OCR tripping rate limits, IP behind a shared NAT/VPN that Google flags, or a Google anti-bot rollout that invalidates the request shape.","solutions":["Inspect LensError.StatusCode and Body: 429 -> back off and retry with jitter honoring Retry-After; 3xx/200-HTML -> re-run cookie seeding before retrying.","Seed/warm cookies before the first ScanByData call so the session looks legitimate.","Throttle concurrent Lens scans to avoid rate limiting.","Check the upstream library for an updated Lens protobuf/endpoint if a 400/404 persists.","Retry once on transient 5xx with exponential backoff."],"exampleFix":"// before\nvar result = await lens.ScanByData(buffer, mime, dims, lang);\n\n// after\ntry { return await lens.ScanByData(buffer, mime, dims, lang); }\ncatch (LensError ex) when (ex.StatusCode == 429)\n{\n    var delay = ex.Headers?.RetryAfter?.Delta ?? TimeSpan.FromSeconds(5);\n    await Task.Delay(delay);\n    return await lens.ScanByData(buffer, mime, dims, lang);\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { return await lens.ScanByData(buffer, mime, dims, lang); }\ncatch (LensError ex)\n{\n    if (ex.StatusCode == 429)\n    {\n        var delay = ex.Headers?.RetryAfter?.Delta ?? TimeSpan.FromSeconds(5);\n        await Task.Delay(delay);\n        return await lens.ScanByData(buffer, mime, dims, lang);\n    }\n    if (ex.StatusCode >= 500) { await Task.Delay(Backoff(attempt)); return await lens.ScanByData(buffer, mime, dims, lang); }\n    throw;\n}","preventionTips":["Warm/seed cookies before the first scan.","Throttle concurrent Lens scans to avoid rate limits.","Honor the Retry-After header on 429 responses.","Keep the library updated when Google changes the endpoint.","Branch on status code rather than treating all failures identically."],"tags":["network","http","google-lens","rate-limit","scraping"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}