chenhg5/cc-connect · error

too many redirects

Error message

too many redirects

What it means

downloadFile (core/updater.go:177) installs an http.Client CheckRedirect hook that fails the request once the redirect chain exceeds 10 hops, returning the literal error `too many redirects`. This guards against infinite or pathological redirect loops when fetching release archives (e.g. GitHub assets redirect through objects.githubusercontent.com). The error surfaces via client.Do and is typically wrapped by error 917.

Source

Thrown at core/updater.go:177

	var err error
	if goos == "windows" {
		binary, err = extractBinaryFromZip(data)
	} else {
		binary, err = extractBinaryFromTarGz(data)
	}
	if err != nil {
		return fmt.Errorf("extract binary: %w", err)
	}

	return replaceBinary(binary)
}

func downloadFile(url string) ([]byte, error) {
	client := &http.Client{
		Timeout: 5 * time.Minute,
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			if len(via) > 10 {
				return fmt.Errorf("too many redirects")
			}
			return nil
		},
	}
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("User-Agent", "cc-connect-updater")

	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("HTTP %d for %s", resp.StatusCode, url)

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Follow the URL manually with `curl -IL --max-redirs 20 <download-url>` to see the redirect chain and find the looping host.
  2. If a corporate proxy causes the loop, bypass it for github.com/objects.githubusercontent.com/gitee.com and retry.
  3. Retry the upgrade later if the loop is on the CDN side — it's usually a transient upstream misconfiguration.
  4. If legitimate chains grow beyond 10, raise the `len(via) > 10` threshold to a higher cap (e.g. 20).
  5. Point the updater at a working mirror (preferGitee toggle) so the looping source is skipped.

Example fix

// before
if len(via) > 10 {
	return fmt.Errorf("too many redirects")
}

// after: include the chain for diagnosis
if len(via) > 10 {
	locs := make([]string, 0, len(via))
	for _, r := range via {
		locs = append(locs, r.URL.String())
	}
	return fmt.Errorf("too many redirects (>10): %s", strings.Join(locs, " -> "))
}
Defensive patterns

Strategy: retry

Validate before calling

func redirectChainOK(u string) error {
	c := &http.Client{
		Timeout: 30 * time.Second,
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			if len(via) > 10 {
				return fmt.Errorf("redirect chain exceeds 10: %d hops via %s", len(via), via[len(via)-1].URL)
			}
			return nil
		},
	}
	resp, err := c.Head(u)
	if err != nil {
		return err
	}
	resp.Body.Close()
	return nil
}

Try / catch

if err := core.SelfUpdate(tag, preferGitee); err != nil {
	if strings.Contains(err.Error(), "too many redirects") {
		slog.Warn("release download stuck in redirect loop; trying mirror", "err", err)
		_ = core.SelfUpdate(tag, !preferGitee) // switch mirror
		return err
	}
	return err
}

Prevention

When it happens

Trigger: The download URL redirects more than 10 times: a redirect loop on the release-asset host, a misconfigured CDN/proxy bouncing between URLs, cookie/auth redirects that never settle, or a rewrite loop on a mirror host. Occurs inside downloadFile during SelfUpdate.

Common situations: Corporate proxies rewriting release-asset URLs back to themselves; Gitee/GitHub CDN misconfiguration; caching middleware in front of the download URL looping HTTP<->HTTPS; testing against a local or staged mirror with a bad redirect config.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/227749eefec48be9. Report an issue: GitHub.