SubtitleEdit/subtitleedit · error · LensError
Lens returned status code {(int)response.StatusCode}
Error message
Lens returned status code {(int)response.StatusCode} What it means
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.
Source
Thrown at src/ui/Logic/Ocr/GoogleLens/LensCore.cs:332
foreach (var kvp in headers)
{
if (kvp.Key.ToLower() != "content-type")
{
request.Headers.TryAddWithoutValidation(kvp.Key, kvp.Value);
}
}
var response = await _fetch!(request);
if (response.Headers.TryGetValues("set-cookie", out var cookies))
{
SetCookies(cookies);
}
if (!response.IsSuccessStatusCode)
{
var errorBody = await response.Content.ReadAsStringAsync();
throw new LensError($"Lens returned status code {(int)response.StatusCode}", (int)response.StatusCode, response.Headers, errorBody);
}
var responseBytes = await response.Content.ReadAsByteArrayAsync();
return LensProtoResponse.Deserialize(responseBytes);
}
public async Task<LensResult> ScanByData(byte[] uint8Array, string mime, int[] originalDimensions, string twoLetterLanguageCode)
{
if (!Constants.SUPPORTED_MIMES.Contains(mime) && mime != "image/gif")
{
Console.WriteLine($"MIME type {mime} might not be directly supported by the proto API, conversion recommended.");
}
var actualDimensions = Helper.ImageDimensionsFromData(uint8Array);
var serializedRequest = CreateLensProtoRequest(uint8Array, actualDimensions.Width, actualDimensions.Height);
var serverResponse = await SendProtoRequest(serializedRequest, twoLetterLanguageCode);
View on GitHub (pinned to 17a9f07487)
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.
Example fix
// before
var result = await lens.ScanByData(buffer, mime, dims, lang);
// after
try { return await lens.ScanByData(buffer, mime, dims, lang); }
catch (LensError ex) when (ex.StatusCode == 429)
{
var delay = ex.Headers?.RetryAfter?.Delta ?? TimeSpan.FromSeconds(5);
await Task.Delay(delay);
return await lens.ScanByData(buffer, mime, dims, lang);
} Defensive patterns
Strategy: retry
Try / catch
try { return await lens.ScanByData(buffer, mime, dims, lang); }
catch (LensError ex)
{
if (ex.StatusCode == 429)
{
var delay = ex.Headers?.RetryAfter?.Delta ?? TimeSpan.FromSeconds(5);
await Task.Delay(delay);
return await lens.ScanByData(buffer, mime, dims, lang);
}
if (ex.StatusCode >= 500) { await Task.Delay(Backoff(attempt)); return await lens.ScanByData(buffer, mime, dims, lang); }
throw;
} Prevention
- 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.
When it happens
Trigger: _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).
Common situations: 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.
Related errors
- Lens returned a non-200 status code
- Lens returned a 302 status code twice
- Location header not found
- Baidu API Error {errorCode}: {errorMsg}
- {StaticName} failed with status code {(int)result.StatusCode
AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13).
Data as JSON: /api/errors/7266d00bec658dac.
Report an issue: GitHub.