chenhg5/cc-connect · error

check updates failed (both sources): %w

Error message

check updates failed (both sources): %w

What it means

This error is returned by fetchReleases (core/updater.go:94) when BOTH release-list sources (GitHub API first, then Gitee as fallback) fail to return a valid release list. The wrapped error (`%w`) is the failure from the second (fallback) source; the primary source's error is only logged at debug level. Callers see it from CheckForUpdate, meaning no update check could be performed at all.

Source

Thrown at core/updater.go:94

		url  string
	}
	sources := []source{
		{"github", githubReleasesAPI + "?per_page=20"},
		{"gitee", giteeReleasesAPI + "?per_page=20&direction=desc&sort=created"},
	}
	if preferGitee {
		sources[0], sources[1] = sources[1], sources[0]
	}

	releases, err := fetchReleasesFrom(sources[0].url)
	if err == nil && len(releases) > 0 {
		return releases, nil
	}
	slog.Debug("updater: primary source failed, trying fallback", "primary", sources[0].name, "error", err)

	releases, err = fetchReleasesFrom(sources[1].url)
	if err != nil {
		return nil, fmt.Errorf("check updates failed (both sources): %w", err)
	}
	return releases, nil
}

func fetchReleasesFrom(apiURL string) ([]ReleaseInfo, error) {
	client := &http.Client{Timeout: 15 * time.Second}
	req, err := http.NewRequest("GET", apiURL, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("User-Agent", "cc-connect-updater")
	req.Header.Set("Accept", "application/json")

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

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Check basic connectivity: `curl -sS https://api.github.com/repos/chenhg5/cc-connect/releases?per_page=1` and the Gitee equivalent to see which source and status code fails.
  2. Set preferGitee=true in config (or use the flag) so the Gitee mirror is tried first if GitHub is blocked in your network.
  3. Inspect the wrapped error text after 'both sources:' — it names the fallback failure (e.g. 'API returned 403', 'context deadline exceeded') and fix that root cause.
  4. If behind a proxy, set HTTPS_PROXY so both hosts are reachable, or temporarily disable automatic update checks.
  5. Retry later if it is a transient outage or GitHub rate limit (403 with Retry-After); rate limits reset hourly.

Example fix

// before: check fails silently on primary, error mentions only fallback
releases, err = fetchReleasesFrom(sources[1].url)
if err != nil {
	return nil, fmt.Errorf("check updates failed (both sources): %w", err)
}

// after: log both errors so the root cause of each source is visible
if err != nil {
	return nil, fmt.Errorf("check updates failed (primary: %v; fallback: %w)", primaryErr, err)
}
Defensive patterns

Strategy: fallback

Validate before calling

func canCheckUpdates() error {
	for _, u := range []string{"https://api.github.com", "https://gitee.com/api/v5"} {
		c := &http.Client{Timeout: 5 * time.Second}
		resp, err := c.Get(u)
		if err == nil {
			resp.Body.Close()
			return nil
		}
	}
	return errors.New("neither github nor gitee API reachable")
}

Try / catch

if best, err := core.CheckForUpdate(version, preferGitee); err != nil {
	var netErr net.Error
	if errors.As(err, &netErr) || strings.Contains(err.Error(), "both sources") {
		slog.Warn("update check skipped; network to release APIs unavailable", "err", err)
	} else {
		slog.Error("update check failed", "err", err)
	}
	// proceed without update — non-fatal
}

Prevention

When it happens

Trigger: Both fetchReleasesFrom calls fail: e.g. no network access, api.github.com blocked (common in mainland China without preferGitee), Gitee API rate-limited or returning non-200 (caught as error 916), 15s HTTP client timeout on both hosts, or both APIs returning malformed JSON that fails to decode into []ReleaseInfo.

Common situations: Developers running cc-connect behind a corporate proxy or firewall that blocks api.github.com while the Gitee fallback is also unreachable; GitHub API rate-limit (HTTP 403) when many checks originate from one IP; DNS failures on an offline host; transient network outage during `cc-connect upgrade` or startup update check.

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


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