tsenart/vegeta · warning

stopped after %d redirects

Error message

stopped after %d redirects

What it means

When an attack is configured with MaxRedirects(n) where n != NoFollow, vegeta installs an http.Client.CheckRedirect that returns this error once the redirect chain exceeds n requests. It is a deliberate policy limit, not an internal failure — the attack records it and continues with subsequent requests.

Source

Thrown at lib/attack.go:149

}

// ChunkedBody returns a functional option which makes the attacker send the
// body of each request with the chunked transfer encoding.
func ChunkedBody(b bool) func(*Attacker) {
	return func(a *Attacker) { a.chunked = b }
}

// Redirects returns a functional option which sets the maximum
// number of redirects an Attacker will follow.
func Redirects(n int) func(*Attacker) {
	return func(a *Attacker) {
		a.redirects = n
		a.client.CheckRedirect = func(_ *http.Request, via []*http.Request) error {
			switch {
			case n == NoFollow:
				return http.ErrUseLastResponse
			case n < len(via):
				return fmt.Errorf("stopped after %d redirects", n)
			default:
				return nil
			}
		}
	}
}

// Proxy returns a functional option which sets the `Proxy` field on
// the http.Client's Transport
func Proxy(proxy func(*http.Request) (*url.URL, error)) func(*Attacker) {
	return func(a *Attacker) {
		tr := a.client.Transport.(*http.Transport)
		tr.Proxy = proxy
	}
}

// Timeout returns a functional option which sets the maximum amount of time
// an Attacker will wait for a request to be responded to and completely read.

View on GitHub (pinned to cf58112690)

Solutions

  1. Increase the limit with a higher MaxRedirects(n) to accommodate the target's chain length.
  2. Use MaxRedirects(-1) (NoFollow) to not follow redirects at all (returns the first non-redirect response instead of this error).
  3. Fix the server-side redirect loop (scheme, trailing slash, cookie/Host handling).
  4. Inspect recorded responses' Location headers to distinguish a loop from a deep chain.

Example fix

// before
attacker.MaxRedirects(2)
// after
attacker.MaxRedirects(10) // or attacker.MaxRedirects(vegeta.NoFollow)
Defensive patterns

Strategy: try-catch

Try / catch

for res := range results {
	if res.Code == 0 && res.Error != "" {
		if strings.Contains(res.Error, "stopped after") {
			// redirect limit hit: raise MaxRedirects or use NoFollow
			continue
		}
	}
	// handle other errors...
}

Prevention

When it happens

Trigger: Hitting a target whose redirect chain is longer than the configured MaxRedirects(n), with n a positive number (not NoFollow/-1). E.g. MaxRedirects(5) against an endpoint redirecting 6+ times.

Common situations: Redirect loops caused by misconfigured TLS/hosts (http->https bouncing), cookie-less clients re-triggering redirects, load balancers redirecting repeatedly, or simply setting the limit too low.

Related errors


AI-assisted analysis of tsenart/vegeta@cf58112690 (2026-08-31). Data as JSON: /api/errors/32c542f87e861384. Report an issue: GitHub.