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
- Raise the cap: const o = new http.Options(); o.MaxRedirects = 25; const c = new http.Client(o);
- Disable following and walk Location yourself: o.DisableRedirects = true, then read resp.GetHeader('Location') per hop
- 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
- Set MaxRedirects per target class instead of relying on the default 10
- Use DisableRedirects when only the first hop matters
- Probe the final URL directly when the redirect target is predictable
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
- http: response body exceeds %d bytes
- http: executionId not set
- http: invalid url: %w
- http: url must include scheme and host
- dialers not initialized for %s
AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15).
Data as JSON: /api/errors/f835ec2b32642ea4.
Report an issue: GitHub.