golang/go · error

stopped after 10 redirects

Error message

stopped after 10 redirects

What it means

checkRedirect is the http.Client.CheckRedirect used for go-get discovery fetches. It mimics net/http's limit of 10 redirects and returns this error once the hop count reaches 10, preventing redirect loops.

Solutions

  1. Fix the vanity server's redirect chain to stay under 10 hops.
  2. Bypass vanity discovery: use the direct VCS URL (e.g. go get github.com/user/repo).
  3. Audit the server for accidental redirect loops.

Example fix

# before
$ go get example.com/lib   # vanity server loops >10 redirects

# after
$ go get github.com/user/lib   # direct VCS path
Defensive patterns

Strategy: validation

Validate before calling

// Cap redirect handling when fetching vanity URLs yourself.
func limitedRedirectClient() *http.Client {
    c := *http.DefaultClient
    c.CheckRedirect = func(req *http.Request, via []*http.Request) error {
        if len(via) >= 10 { return errors.New("too many redirects") }
        return nil
    }
    return &c
}

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: Fetching a vanity-import page (or module URL) whose redirect chain exceeds 10 hops.

Common situations: Misconfigured vanity servers with redirect loops; aggressive CDN/load-balancer redirects; HTTP->HTTPS cascades.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/e4bf78e5237e2903. Report an issue: GitHub.

Appendix: source

Thrown at src/cmd/go/internal/web/http.go:71

// but rejects redirects to plain-HTTP URLs if the original URL was secure.
func securityPreservingHTTPClient(original *http.Client) *http.Client {
	c := new(http.Client)
	*c = *original
	c.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		if len(via) > 0 && via[0].URL.Scheme == "https" && req.URL.Scheme != "https" {
			lastHop := via[len(via)-1].URL
			return fmt.Errorf("redirected from secure URL %s to insecure URL %s", lastHop, req.URL)
		}
		return checkRedirect(req, via)
	}
	return c
}

func checkRedirect(req *http.Request, via []*http.Request) error {
	// Go's http.DefaultClient allows 10 redirects before returning an error.
	// Mimic that behavior here.
	if len(via) >= 10 {
		return errors.New("stopped after 10 redirects")
	}
	hasGoGet1 := via[len(via)-1].URL.Query().Get("go-get") == "1"
	if hasGoGet1 {
		if len(req.URL.RawQuery) > 0 {
			req.URL.RawQuery += "&"
		}
		req.URL.RawQuery += "go-get=1"
	}

	intercept.Request(req)
	return nil
}

func get(security SecurityMode, url *urlpkg.URL) (*Response, error) {
	start := time.Now()

	if url.Scheme == "file" {
		return getFile(url)

View on GitHub (pinned to b6b368adc5)