jeessy2/ddns-go · error

could not download release from %s: %v

Error message

could not download release from %s: %v

What it means

downloadAssetFromURL in util/update/package.go performs client.Get(url) with the shared HTTP client; if the transport-level request itself fails, it wraps the cause with the URL using %v. This means DNS failure, connection refused/timeout, TLS errors, or context cancellation prevented even receiving an HTTP response.

Source

Thrown at util/update/package.go:68

// to 从 assetURL 下载可执行文件,并用下载的文件替换当前的可执行文件。
// 这个函数是用于更新二进制文件的低级 API。因为它不使用源提供者,而是直接通过 HTTP 从 URL 下载 asset 。
// 所以这个函数不能用于更新私有仓库的 release。
// cmdPath 是命令可执行文件的文件路径。
func to(assetURL, assetFileName, cmdPath string) error {
	src, err := downloadAssetFromURL(assetURL)
	if err != nil {
		return err
	}
	defer src.Close()
	return decompressAndUpdate(src, assetFileName, cmdPath)
}

func downloadAssetFromURL(url string) (rc io.ReadCloser, err error) {
	client := util.CreateHTTPClient()
	resp, err := client.Get(url)
	if err != nil {
		return nil, fmt.Errorf("could not download release from %s: %v", url, err)
	}
	if resp.StatusCode >= 300 {
		resp.Body.Close()
		return nil, fmt.Errorf("could not download release from %s. Response code: %d", url, resp.StatusCode)
	}

	return resp.Body, nil
}

View on GitHub (pinned to 5874c2e666)

Solutions

  1. Check network connectivity and DNS for the release host (curl -I <url>).
  2. Inspect the wrapped %v cause to identify DNS vs connection vs TLS failure and fix accordingly (proxy env HTTPS_PROXY, VPN, /etc/hosts).
  3. Correct the release asset URL in the update configuration if it points to a nonexistent host.
  4. Add retry with backoff around downloadAssetFromURL for transient network errors.

Example fix

// before
rc, err := to(assetURL)
// after
var rc io.ReadCloser
for i := 0; i < 3 && rc == nil; i++ {
	rc, err = to(assetURL)
	if err != nil {
		time.Sleep(time.Duration(1<<i) * time.Second)
	}
}
Defensive patterns

Strategy: retry

Validate before calling

// before calling the updater
urlObj, err := neturl.Parse(assetURL)
if err != nil || urlObj.Scheme != "https" {
	return fmt.Errorf("invalid asset URL: %s", assetURL)
}
// connectivity precheck
resp, err := http.Head(assetURL)
if err != nil {
	return fmt.Errorf("release host unreachable: %v", err)
}

Try / catch

var lastErr error
for attempt := 0; attempt < 3; attempt++ {
	rc, err := downloadAssetFromURL(url)
	if err == nil { return rc, nil }
	lastErr = err
	time.Sleep(time.Duration(1<<attempt) * time.Second)
}
return nil, fmt.Errorf("download failed after retries: %w", lastErr)

Prevention

When it happens

Trigger: client.Get(url) returns a non-nil err — no HTTP status was obtained. Raised from downloadAssetFromURL and propagated to its caller to() during the update download step.

Common situations: Offline machine or broken DNS; firewall/proxy blocking the release host (e.g. github.com); wrong release URL configured; TLS certificate problems; request deadline exceeded on slow networks.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of jeessy2/ddns-go@5874c2e666 (2026-09-03). Data as JSON: /api/errors/6ec4fe50b41a4e2f. Report an issue: GitHub.