siyuan-note/siyuan · error

download failed: %s

Error message

download failed: %s

What it means

Thrown by fetchBytes when httpclient.NewBrowserRequest().Get returns a non-nil error before any response is obtained. This is a transport-level failure (DNS, connection refused, TLS handshake, timeout, proxy), not an HTTP status error.

Source

Thrown at kernel/util/skill.go:403

	// codeload main 分支 404 时回退 master
	if src.isZip && src.branch == "main" {
		ownerRepo := strings.TrimPrefix(strings.TrimPrefix(src.downloadURL, "https://codeload.github.com/"), "http://codeload.github.com/")
		ownerRepo = strings.TrimSuffix(ownerRepo, "/zip/refs/heads/main")
		fallback := codeloadSource(ownerRepo, "master")
		data, contentType, ferr := fetchBytes(fallback.downloadURL)
		if ferr != nil {
			return nil, "", fmt.Errorf("download failed (tried main and master): %v", err)
		}
		return data, contentType, nil
	}
	return nil, "", err
}

// fetchBytes 执行带大小限制的 GET
func fetchBytes(rawURL string) (data []byte, contentType string, err error) {
	resp, err := httpclient.NewBrowserRequest().Get(rawURL)
	if err != nil {
		return nil, "", errors.New("download failed: " + err.Error())
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 400 {
		return nil, "", fmt.Errorf("download failed: HTTP %d", resp.StatusCode)
	}

	contentType = resp.Header.Get("Content-Type")
	body, err := io.ReadAll(io.LimitReader(resp.Body, maxSkillDownloadBytes+1))
	if err != nil {
		return nil, "", errors.New("read body failed: " + err.Error())
	}
	if len(body) > maxSkillDownloadBytes {
		return nil, "", errors.New("skill source too large (limit 10MB)")
	}
	return body, contentType, nil
}

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Check network connectivity and DNS resolution for the target host.
  2. Verify proxy/TLS configuration in the environment (httpclient honors standard proxy env vars).
  3. Retry with exponential backoff for transient failures.
  4. For TLS errors, confirm the system CA store is up to date.
Defensive patterns

Strategy: retry

Try / catch

// retry transient transport errors with backoff
var res *util.InstallSkillResult
var err error
for attempt := 0; attempt < 3; attempt++ {
    res, err = util.InstallSkill(src)
    if err == nil || !strings.HasPrefix(err.Error(), "download failed:") {
        break
    }
    time.Sleep(time.Duration(1<<attempt) * time.Second)
}

Prevention

When it happens

Trigger: DNS resolution fails for the host; the server is unreachable (connection refused/timeout); TLS certificate is invalid; a proxy blocks the request; the local network is down.

Common situations: Air-gapped or proxied environments; self-signed or expired TLS certs; corporate firewall blocking codeload/raw.githubusercontent.com; transient connectivity loss.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/7c57173fc7fe411a. Report an issue: GitHub.