SubtitleEdit/subtitleedit · error · CoreError
Lens returned a 302 status code twice
Error message
Lens returned a 302 status code twice
What it means
Thrown by Core.FetchAsync when Google Lens responds with HTTP 302 (Found) on the retry pass (secondTry == true). The first 302 triggers a consent-screen handshake (posting to consent.google.com/save and retrying); a second consecutive 302 means the consent flow did not establish a usable session, so the client gives up rather than loop indefinitely. Wrapped in CoreError carrying status, headers, and response text.
Source
Thrown at src/ui/Logic/Ocr/GoogleLens/Core.cs:162
responseBytes = Helper.DecompressDeflate(responseBytes);
}
if (response.Content.Headers.ContentEncoding.Contains("br"))
{
responseBytes = Helper.DecompressBrotli(responseBytes);
}
var responseBody = Encoding.UTF8.GetString(responseBytes);
if (response.Headers.TryGetValues("set-cookie", out var setCookieValues))
{
SetCookies(setCookieValues);
}
if (response.StatusCode == System.Net.HttpStatusCode.Found)
{
if (secondTry)
{
throw new CoreError("Lens returned a 302 status code twice", (int)response.StatusCode, response.Headers, text);
}
var consentHeaders = HeaderData.GenerateHeaders();
consentHeaders["Content-Type"] = "application/x-www-form-urlencoded";
consentHeaders["Referer"] = "https://consent.google.com/";
consentHeaders["Origin"] = "https://consent.google.com";
GenerateCookieHeader(consentHeaders);
var location = response.Headers.Location;
if (location == null)
{
throw new Exception("Location header not found");
}
var redirectLink = new Uri(location.ToString());
var params2 = new Dictionary<string, string>
{View on GitHub (pinned to 17a9f07487)
Solutions
- Ensure the HTTP client (HttpClientFactoryWithProxy.CreateHttpClientWithProxy) honors cookies and redirects are not auto-followed.
- Update the consent parameters / endpoint tokens if Google changed them.
- Retry the whole OCR call after a delay, or fall back to a different OCR engine.
- Inspect the CoreError response text and headers to see where the redirect points.
Example fix
// before
var result = await core.FetchAsync(formdata, dims);
// after
try { var result = await core.FetchAsync(formdata, dims); }
catch (CoreError ex) when (ex.Message.Contains("302 twice")) { return await FallbackOcrAsync(image); } Defensive patterns
Strategy: retry
Validate before calling
// Cannot fully prevent a server-side 302, but ensure cookies are enabled: var client = HttpClientFactoryWithProxy.CreateHttpClientWithProxy(); // verify it uses a CookieContainer // Ensure HttpClient does not auto-follow redirects (so the consent flow can run).
Try / catch
try { var r = await core.FetchAsync(formdata, dims); }
catch (CoreError ex) when (ex.Message.Contains("302 status code twice"))
{ await Task.Delay(2000); return await RetryOrFallbackAsync(); } Prevention
- Confirm the HTTP client honors Set-Cookie and does not auto-follow redirects.
- Keep the consent 'bl' token current if Google rotates it.
- Retry with backoff on transient redirect loops.
- Provide a fallback OCR engine when Lens session setup fails.
When it happens
Trigger: Repeated 302 redirects from Lens after the consent handshake — e.g. cookies were not accepted, the consent POST itself redirected again, or Google changed the consent flow. Network/proxy environments that strip Set-Cookie headers also cause this.
Common situations: A proxy or corporate firewall dropping Set-Cookie; an outdated hardcoded consent 'bl' token (boq_identityfrontenduiserver_20240129.02_p0) that Google rotated; regional consent requirements the handshake does not satisfy; rate limiting returning redirects.
Related errors
- Lens returned a non-200 status code
- Location header not found
- Ollama returned {(int)resp.StatusCode}: {json}
- Could not parse response: {e.Message}
- Lens returned status code {(int)response.StatusCode}
AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13).
Data as JSON: /api/errors/5dde74543784aeb1.
Report an issue: GitHub.