{"record":{"id":"9dad3c4be2f8c249","repo":"chenhg5/cc-connect","slug":"extract-binary-w","errorCode":null,"errorMessage":"extract binary: %w","messagePattern":"extract binary: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/updater.go","lineNumber":166,"sourceCode":"\t\tdata, lastErr = downloadFile(u)\n\t\tif lastErr == nil {\n\t\t\tbreak\n\t\t}\n\t\tslog.Debug(\"updater: download failed, trying next\", \"error\", lastErr)\n\t}\n\tif lastErr != nil && data == nil {\n\t\treturn fmt.Errorf(\"download failed from all sources: %w\", lastErr)\n\t}\n\n\tvar binary []byte\n\tvar err error\n\tif goos == \"windows\" {\n\t\tbinary, err = extractBinaryFromZip(data)\n\t} else {\n\t\tbinary, err = extractBinaryFromTarGz(data)\n\t}\n\tif err != nil {\n\t\treturn fmt.Errorf(\"extract binary: %w\", err)\n\t}\n\n\treturn replaceBinary(binary)\n}\n\nfunc downloadFile(url string) ([]byte, error) {\n\tclient := &http.Client{\n\t\tTimeout: 5 * time.Minute,\n\t\tCheckRedirect: func(req *http.Request, via []*http.Request) error {\n\t\t\tif len(via) > 10 {\n\t\t\t\treturn fmt.Errorf(\"too many redirects\")\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t}\n\treq, err := http.NewRequest(\"GET\", url, nil)\n\tif err != nil {\n\t\treturn nil, err","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/updater.go#L148-L184","documentation":"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`.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","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.","Re-run the upgrade; transient truncation usually resolves on retry, or switch sources with preferGitee.","Check disk space / memory — very large truncated bodies can also fail decode.","If a proxy returns 200 HTML pages, bypass the proxy for release download hosts."],"exampleFix":"// before: silently accepts any 200 body, even HTML\nif resp.StatusCode != http.StatusOK {\n\treturn nil, fmt.Errorf(\"HTTP %d for %s\", resp.StatusCode, url)\n}\nreturn io.ReadAll(resp.Body)\n\n// after: sanity-check the payload looks like gzip before returning\nif resp.StatusCode != http.StatusOK {\n\treturn nil, fmt.Errorf(\"HTTP %d for %s\", resp.StatusCode, url)\n}\ndata, err := io.ReadAll(resp.Body)\nif err == nil && len(data) > 2 && data[0] != 0x1f && data[1] != 0x8b && runtime.GOOS != \"windows\" {\n\treturn nil, fmt.Errorf(\"downloaded payload for %s is not a gzip archive\", url)\n}\nreturn data, err","handlingStrategy":"validation","validationCode":"func looksLikeArchive(data []byte, windows bool) error {\n\tif len(data) < 4 {\n\t\treturn errors.New(\"archive too small\")\n\t}\n\tif windows {\n\t\tif data[0] != 'P' || data[1] != 'K' {\n\t\t\treturn errors.New(\"not a zip archive (proxy HTML page?)\")\n\t\t}\n\t\treturn nil\n\t}\n\tif data[0] != 0x1f || data[1] != 0x8b {\n\t\treturn errors.New(\"not a gzip archive (proxy HTML page?)\")\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"if err := core.SelfUpdate(tag, preferGitee); err != nil {\n\tif strings.Contains(err.Error(), \"extract binary\") {\n\t\tslog.Error(\"downloaded archive invalid — no install attempted\", \"err\", err)\n\t\t// check for proxy-intercepted payload or renamed inner binary, then retry\n\t}\n\treturn err\n}","preventionTips":["Verify with `file`/magic bytes that the downloaded asset is really tar.gz or zip before extraction.","Ensure releases keep a regular file whose base name starts with `cc-connect` in the archive.","Bypass proxies that return 200 HTML error/captcha pages for release download hosts.","Retry truncated downloads; verify content-length against the asset size when possible.","Don't mix .zip and .tar.gz assets across platforms — keep the GOOS-based extension logic."],"tags":["archive","tar","gzip","zip","updater","extraction"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}