projectdiscovery/nuclei · warning

http: stopped after %d redirects

Error message

http: stopped after %d redirects

What it means

FollowRedirects is on (the Client default) and the redirect chain exceeded MaxRedirects (default 10), so the CheckRedirect hook aborts. Every hop is also re-checked against host policy, so this cap bounds both redirect loops and policy-evading chains. The error is raised by net/http's redirect machinery and surfaces from Get/Post/Request.

Source

Thrown at pkg/js/libs/http/http.go:315

		ResponseHeaderTimeout: time.Duration(c.TimeoutSeconds) * time.Second,
	}

	httpClient := &http.Client{
		Transport: transport,
		Timeout:   time.Duration(c.TimeoutSeconds) * time.Second,
	}
	if c.jar != nil {
		httpClient.Jar = c.jar
	}
	if !c.FollowRedirects {
		httpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
			return http.ErrUseLastResponse
		}
	} else {
		max := c.MaxRedirects
		httpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
			if len(via) >= max {
				return fmt.Errorf("http: stopped after %d redirects", max)
			}
			if nextHost := req.URL.Hostname(); nextHost != "" && !protocolstate.IsHostAllowed(executionID, nextHost) {
				return protocolstate.ErrHostDenied.Msgf(nextHost)
			}
			return nil
		}
	}

	var bodyReader io.Reader
	if body != "" && method != http.MethodHead && method != http.MethodGet {
		bodyReader = strings.NewReader(body)
	}

	req, err := http.NewRequestWithContext(ctx, method, parsed.String(), bodyReader)
	if err != nil {
		return nil, err
	}
	for k, vals := range c.headers {

View on GitHub (pinned to 265b3a3dec)

Solutions

  1. Raise the cap: const o = new http.Options(); o.MaxRedirects = 25; const c = new http.Client(o);
  2. Disable following and walk Location yourself: o.DisableRedirects = true, then read resp.GetHeader('Location') per hop
  3. Probe the final URL directly when it is predictable, skipping the chain

Example fix

// before: default cap of 10, deep auth chain
const client = new http.Client();
const resp = client.Get('https://acme.com/'); // -> stopped after 10 redirects

// after: raise the cap for targets known to hop a lot
const o = new http.Options();
o.MaxRedirects = 25;
const client = new http.Client(o);
const resp = client.Get('https://acme.com/');
Defensive patterns

Strategy: fallback

Validate before calling

const o = new http.Options();
o.MaxRedirects = 25; // set above the known chain depth for auth-heavy targets
const client = new http.Client(o);

Try / catch

let resp;
try {
  resp = client.Get(url);
} catch (e) {
  if (/stopped after \d+ redirects/.test(e.message || '')) {
    const o = new http.Options();
    o.DisableRedirects = true;
    const first = new http.Client(o).Get(url); // stop following; walk Location headers manually
  }
}

Prevention

When it happens

Trigger: Auth flows bouncing between /login, /auth, and an IdP more than 10 times; CDN/geo chains (http->https->host->www) forming a cycle; Options.MaxRedirects set lower than the chain depth of the target.

Common situations: SAML/OAuth-protected targets with deep redirect chains; marketing/geo redirects looping between regions; templates using the default client where the first request legitimately hops more than 10 times.

Related errors


AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15). Data as JSON: /api/errors/f835ec2b32642ea4. Report an issue: GitHub.