Tencent/WeKnora · error
stopped after %d redirects
Error message
stopped after %d redirects
What it means
This error comes from the CheckRedirect policy (newSSRFCheckRedirect) when a request chain exceeds maxRedirects hops — mirroring net/http's own 'stopped after N redirects' behavior. It means the server is redirecting in a loop or an excessive chain, and the client aborts rather than following indefinitely.
Source
Thrown at internal/utils/security.go:708
// redirect policy — those live on the *http.Client — so a single transport can
// be shared across many clients to pool keep-alive connections globally.
func NewSSRFSafeTransport(config SSRFSafeHTTPClientConfig) *http.Transport {
return &http.Transport{
DisableKeepAlives: config.DisableKeepAlives,
DisableCompression: config.DisableCompression,
// Dial with SSRF protection - validates resolved IPs before connecting
DialContext: SSRFSafeDialContext,
}
}
// newSSRFCheckRedirect returns a CheckRedirect policy that enforces the redirect
// count limit, strips sensitive headers on cross-host hops, and re-validates
// every redirect target against SSRF protections.
func newSSRFCheckRedirect(maxRedirects int) func(*http.Request, []*http.Request) error {
return func(req *http.Request, via []*http.Request) error {
// Check redirect count
if len(via) >= maxRedirects {
return fmt.Errorf("stopped after %d redirects", maxRedirects)
}
// Strip credentials when the redirect crosses hosts so connector
// tokens (e.g. Yuque X-Auth-Token) cannot leak to a third party.
if len(via) > 0 && !sameHTTPOrigin(via[0].URL, req.URL) {
stripRedirectSensitiveHeaders(req)
}
// Validate the redirect target URL for SSRF (whitelist-aware).
// Even whitelisted hosts must use http/https to prevent scheme-based attacks.
redirectScheme := strings.ToLower(req.URL.Scheme)
if redirectScheme != "http" && redirectScheme != "https" {
return fmt.Errorf("%w: invalid scheme %s", ErrSSRFRedirectBlocked, redirectScheme)
}
redirectHost := req.URL.Hostname()
if redirectHost != "" && IsSSRFWhitelisted(redirectHost) {
return nil
}View on GitHub (pinned to 988cbb0330)
Solutions
- Increase maxRedirects if the chain is legitimately long.
- Break the redirect loop: fix the server/proxy configuration causing repeated 3xxs.
- Request the final URL directly instead of following a long chain.
- Send required auth/cookies so the server stops redirecting.
Example fix
// before
client := &http.Client{Transport: base}
// after
client := &http.Client{
Transport: base,
CheckRedirect: secutils.NewSSRFCheckRedirect(10), // raise limit
} Defensive patterns
Strategy: retry
Validate before calling
// no pre-call validation possible; bounded by client config maxRedirects := 10 // set explicitly when constructing the client
Try / catch
if err != nil && strings.Contains(err.Error(), "stopped after") {
return fmt.Errorf("redirect loop or chain too long for %s: %w", req.URL, err)
} Prevention
- Set an explicit, generous maxRedirects (e.g. 10).
- Fix server-side redirect loops (auth bounce, proxy alternation).
- Request the canonical final URL directly when known.
- Ensure cookies/auth headers survive so the server stops redirecting.
When it happens
Trigger: Any request through an SSRF-safe client configured with newSSRFCheckRedirect(maxRedirects) where the server responds with more than maxRedirects consecutive 3xx responses.
Common situations: Redirect loops caused by cookie-less auth bouncing between login and target, misconfigured reverse proxies alternating redirects, or http→https→www chains longer than the limit.
Related errors
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/6160b1ae4a36fa47.
Report an issue: GitHub.