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

  1. Increase maxRedirects if the chain is legitimately long.
  2. Break the redirect loop: fix the server/proxy configuration causing repeated 3xxs.
  3. Request the final URL directly instead of following a long chain.
  4. 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

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.