chenhg5/cc-connect · error

extract binary: %w

Error message

extract binary: %w

What it means

SelfUpdate (core/updater.go:166) wraps any failure to extract the cc-connect binary from the downloaded archive as `extract binary: %w`. For non-Windows the archive is parsed as tar.gz (extractBinaryFromTarGz), for Windows as zip (extractBinaryFromZip). The extractor fails if the data isn't a valid gzip/tar/zip stream, is truncated, or contains no regular file whose base name starts with `cc-connect`.

Source

Thrown at core/updater.go:166

		data, lastErr = downloadFile(u)
		if lastErr == nil {
			break
		}
		slog.Debug("updater: download failed, trying next", "error", lastErr)
	}
	if lastErr != nil && data == nil {
		return fmt.Errorf("download failed from all sources: %w", lastErr)
	}

	var binary []byte
	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

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Inspect the wrapped cause: gzip/zip header errors mean the payload isn't an archive (likely HTML from a proxy) — download the URL manually with curl and `file` it to confirm.
  2. Verify the archive actually contains a binary whose base name starts with `cc-connect` (`tar tzf` / `unzip -l`); if the release renamed it, fix the asset naming or the prefix check.
  3. Re-run the upgrade; transient truncation usually resolves on retry, or switch sources with preferGitee.
  4. Check disk space / memory — very large truncated bodies can also fail decode.
  5. If a proxy returns 200 HTML pages, bypass the proxy for release download hosts.

Example fix

// before: silently accepts any 200 body, even HTML
if resp.StatusCode != http.StatusOK {
	return nil, fmt.Errorf("HTTP %d for %s", resp.StatusCode, url)
}
return io.ReadAll(resp.Body)

// after: sanity-check the payload looks like gzip before returning
if resp.StatusCode != http.StatusOK {
	return nil, fmt.Errorf("HTTP %d for %s", resp.StatusCode, url)
}
data, err := io.ReadAll(resp.Body)
if err == nil && len(data) > 2 && data[0] != 0x1f && data[1] != 0x8b && runtime.GOOS != "windows" {
	return nil, fmt.Errorf("downloaded payload for %s is not a gzip archive", url)
}
return data, err
Defensive patterns

Strategy: validation

Validate before calling

func looksLikeArchive(data []byte, windows bool) error {
	if len(data) < 4 {
		return errors.New("archive too small")
	}
	if windows {
		if data[0] != 'P' || data[1] != 'K' {
			return errors.New("not a zip archive (proxy HTML page?)")
		}
		return nil
	}
	if data[0] != 0x1f || data[1] != 0x8b {
		return errors.New("not a gzip archive (proxy HTML page?)")
	}
	return nil
}

Try / catch

if err := core.SelfUpdate(tag, preferGitee); err != nil {
	if strings.Contains(err.Error(), "extract binary") {
		slog.Error("downloaded archive invalid — no install attempted", "err", err)
		// check for proxy-intercepted payload or renamed inner binary, then retry
	}
	return err
}

Prevention

When it happens

Trigger: downloadFile succeeded but returned a non-archive payload: a 200 HTML error/captcha page from an intercepting proxy, a truncated download, a corrupt/renamed release asset, or an archive that lacks a file matching the `cc-connect` name prefix (extractBinaryFromTarGz:223 / Zip:242 return 'cc-connect binary not found...'). Triggered during SelfUpdate for the current GOOS.

Common situations: Corporate proxies or captive portals returning HTML with status 200; partially downloaded archives over flaky links; release packaging changes that rename the inner binary (e.g. to `agent` or a versioned name); CDN serving an error page; mixing up .zip/.tar.gz for the wrong OS.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


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