{"record":{"id":"ac8295ecff4beab2","repo":"multica-ai/multica","slug":"http-d-from-s","errorCode":null,"errorMessage":"HTTP %d from %s","messagePattern":"HTTP (.+?) from (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/internal/cli/update.go","lineNumber":359,"sourceCode":"\tif timeout <= 0 {\n\t\treturn DefaultUpdateDownloadTimeout\n\t}\n\treturn timeout\n}\n\n// fetchURLBytes does a GET with the given timeout and returns the response\n// body in full. Used for the checksum manifest (tiny) and the release\n// archive (single-digit MB). The checksum verification path requires buffered\n// bytes so streaming would just push the buffer into the caller anyway.\nfunc fetchURLBytes(url string, timeout time.Duration) ([]byte, error) {\n\tclient := &http.Client{Timeout: updateDownloadTimeoutOrDefault(timeout)}\n\tresp, err := client.Get(url)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"HTTP %d from %s\", resp.StatusCode, url)\n\t}\n\treturn io.ReadAll(resp.Body)\n}\n\n// UpdateViaDownload downloads the latest release binary from GitHub and replaces\n// the current executable in-place. Returns the combined output message and any error.\nfunc UpdateViaDownload(targetVersion string) (string, error) {\n\treturn UpdateViaDownloadWithTimeout(targetVersion, DefaultUpdateDownloadTimeout)\n}\n\n// UpdateViaDownloadWithTimeout downloads the latest release binary with a caller-selected timeout.\nfunc UpdateViaDownloadWithTimeout(targetVersion string, downloadTimeout time.Duration) (string, error) {\n\t// Determine current binary path.\n\texePath, err := selfexec.Resolve()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"resolve executable path: %w\", err)\n\t}\n\texePath, err = filepath.EvalSymlinks(exePath)","sourceCodeStart":341,"sourceCodeEnd":377,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/cli/update.go#L341-L377","documentation":"fetchURLBytes performs an HTTP GET with a timeout and returns 'HTTP %d from %s' whenever the response status is not 200. It is the shared fetcher for the checksum manifest and the release archive, so any non-OK status from the GitHub release CDN surfaces here. The URL is included, so you can tell exactly which artifact failed.","triggerScenarios":"404 when the asset URL is stale or the release is a draft (draft assets need auth); 403 when GitHub API rate limits are exceeded; 5xx from the CDN during publish propagation; redirects to a deleted asset after a release was re-published.","commonSituations":"A half-published GoReleaser run where checksums.txt or the archive lags behind the tag; running the updater on many machines behind one NAT so the shared rate limit trips; pinning a targetVersion whose release assets were later replaced.","solutions":["Check the embedded URL — is it the asset that actually exists on the release page (tag matches, asset name matches GOOS/GOARCH)?","For 403 rate limiting, wait for the rate-limit window to reset or authenticate GitHub requests via a token.","For 404 on a freshly cut release, wait for the release pipeline to finish uploading all assets, then retry — the poller's next tick retries automatically.","For persistent 5xx, retry with backoff or switch networks; CDN failures are usually transient."],"exampleFix":"null","handlingStrategy":"retry","validationCode":null,"typeGuard":"func isHTTPStatusErr(err error) (int, bool) {\n    // matches the fmt.Errorf(\"HTTP %d from %s\", ...) convention\n    var se *neturl.Error\n    if errors.As(err, &se) {\n        return 0, false\n    }\n    m := regexp.MustCompile(`^HTTP (\\d+) from `).FindStringSubmatch(err.Error())\n    if m == nil {\n        return 0, false\n    }\n    n, _ := strconv.Atoi(m[1])\n    return n, true\n}","tryCatchPattern":"data, err := fetchURLBytes(url, timeout)\nif err != nil {\n    if code, ok := isHTTPStatusErr(err); ok && (code == 403 || code >= 500) {\n        // rate-limited or server-side: safe to retry after a delay\n        time.Sleep(30 * time.Second)\n        data, err = fetchURLBytes(url, timeout)\n    }\n    if err != nil {\n        return fmt.Errorf(\"fetch %s: %w\", url, err)\n    }\n}","preventionTips":["Treat 403 from api.github.com as rate limiting: authenticate requests or lower poll frequency","Wait for release pipelines to fully publish assets before triggering updates","Retry 5xx with backoff; treat 404 as a permanent condition, not transient"],"tags":["http","github","network","download"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}