GopeedLab/gopeed · error
too many redirects
Error message
too many redirects
What it means
In the same redirect policy (pkg/download/engine/inject/xhr/module.go:246-248), once more than 20 redirects have been followed for a single request (len(via) > 20), the http client stops and returns 'too many redirects'. This mirrors the browser/fetch safety limit and protects against redirect loops between two or more URLs.
Source
Thrown at pkg/download/engine/inject/xhr/module.go:247
if contentType != "" && (!isStringBody || xhr.requestHeaders.Get("Content-Type") == "") {
reqBuilder.SetHeader("Content-Type", contentType)
}
// Set timeout
if xhr.Timeout > 0 {
xhr.client.SetTimeout(time.Duration(xhr.Timeout) * time.Millisecond)
}
// Configure redirect behavior
xhr.client.SetRedirectPolicy(func(req *http.Request, via []*http.Request) error {
if xhr.Redirect == redirectManual {
return http.ErrUseLastResponse
}
if xhr.Redirect == redirectError {
return errors.New("redirect failed")
}
if len(via) > 20 {
return errors.New("too many redirects")
}
return nil
})
// Execute request
resp, err := reqBuilder.Send(xhr.method, xhr.url)
if err != nil {
// handle timeout error
var ne net.Error
if errors.As(err, &ne) && ne.Timeout() {
if xhr.Timeout > 0 {
xhr.Upload.callOntimeout()
xhr.callOntimeout()
}
return
}
xhr.Upload.callOnerror()
xhr.callOnerror()View on GitHub (pinned to 7b7327ffb3)
Solutions
- Trace the chain: run with redirect:'manual' in a loop (max ~5) and log each Location to find the loop pair
- Fix the loop server-side (canonicalize host/scheme, correct rewrite rules)
- If auth-bounce, attach the needed Cookie/Authorization header in the script's fetch options so the target stops redirecting
- Request the final destination URL directly once identified
Example fix
// before (script)
const r = await fetch('http://a.example/file') // a <-> b redirect loop -> "too many redirects"
// after (script)
let u = 'http://a.example/file'
for (let i = 0; i < 5; i++) {
const m = await fetch(u, { redirect: 'manual' })
if (m.status < 300 || m.status >= 400) break
console.log('hop:', u, '->', m.headers.get('location'))
u = new URL(m.headers.get('location'), u).href
}
const r = await fetch(u) Defensive patterns
Strategy: try-catch
Validate before calling
// Script-side: bounded manual follow to detect loops before the 20-hop limit
async function fetchBounded(url, maxHops = 5) {
let u = url
for (let i = 0; i <= maxHops; i++) {
const m = await fetch(u, { redirect: 'manual' })
if (m.status < 300 || m.status >= 400) return m
const loc = m.headers.get('location')
if (!loc) throw new Error('redirect without location')
u = new URL(loc, u).href
}
throw new Error('redirect loop suspected at ' + u)
} Try / catch
try {
const r = await fetch(url) // follow
} catch (e) {
if (String(e).includes('too many redirects')) {
// hop-trace manually (see validationCode) to find the loop pair, then request the final URL directly
}
} Prevention
- Trace short redirect chains manually with redirect:'manual' to catch loops early
- Forward session cookies/auth headers so auth redirects terminate
- Fix server-side canonicalization (single host/scheme) instead of chasing long chains
When it happens
Trigger: Two URLs redirecting to each other (A -> B -> A ...) with redirect:'follow'; a redirect chain longer than 20 hops (common with ad/tracking chains or auth gates); a server that rewrites a URL and redirects to the rewritten form which again fails the rewrite; cookies/auth not being forwarded so the target keeps bouncing back to login -> original URL.
Common situations: Login-protected download URLs where the injected client lacks the session cookie, producing an infinite auth bounce; misconfigured vhosts alternating between www/non-www or http/https; CDN chains; relative Location headers that resolve back onto the redirecting endpoint.
Related errors
AI-assisted analysis of GopeedLab/gopeed@7b7327ffb3 (2026-08-16).
Data as JSON: /api/errors/b9267f2ea93cf7ec.
Report an issue: GitHub.