multica-ai/multica · error
HTTP %d from %s
Error message
HTTP %d from %s
What it means
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.
Source
Thrown at server/internal/cli/update.go:359
if timeout <= 0 {
return DefaultUpdateDownloadTimeout
}
return timeout
}
// fetchURLBytes does a GET with the given timeout and returns the response
// body in full. Used for the checksum manifest (tiny) and the release
// archive (single-digit MB). The checksum verification path requires buffered
// bytes so streaming would just push the buffer into the caller anyway.
func fetchURLBytes(url string, timeout time.Duration) ([]byte, error) {
client := &http.Client{Timeout: updateDownloadTimeoutOrDefault(timeout)}
resp, err := client.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("HTTP %d from %s", resp.StatusCode, url)
}
return io.ReadAll(resp.Body)
}
// UpdateViaDownload downloads the latest release binary from GitHub and replaces
// the current executable in-place. Returns the combined output message and any error.
func UpdateViaDownload(targetVersion string) (string, error) {
return UpdateViaDownloadWithTimeout(targetVersion, DefaultUpdateDownloadTimeout)
}
// UpdateViaDownloadWithTimeout downloads the latest release binary with a caller-selected timeout.
func UpdateViaDownloadWithTimeout(targetVersion string, downloadTimeout time.Duration) (string, error) {
// Determine current binary path.
exePath, err := selfexec.Resolve()
if err != nil {
return "", fmt.Errorf("resolve executable path: %w", err)
}
exePath, err = filepath.EvalSymlinks(exePath)View on GitHub (pinned to 2c0912b6ec)
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.
Example fix
null
Defensive patterns
Strategy: retry
Type guard
func isHTTPStatusErr(err error) (int, bool) {
// matches the fmt.Errorf("HTTP %d from %s", ...) convention
var se *neturl.Error
if errors.As(err, &se) {
return 0, false
}
m := regexp.MustCompile(`^HTTP (\d+) from `).FindStringSubmatch(err.Error())
if m == nil {
return 0, false
}
n, _ := strconv.Atoi(m[1])
return n, true
} Try / catch
data, err := fetchURLBytes(url, timeout)
if err != nil {
if code, ok := isHTTPStatusErr(err); ok && (code == 403 || code >= 500) {
// rate-limited or server-side: safe to retry after a delay
time.Sleep(30 * time.Second)
data, err = fetchURLBytes(url, timeout)
}
if err != nil {
return fmt.Errorf("fetch %s: %w", url, err)
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/ac8295ecff4beab2.
Report an issue: GitHub.