siyuan-note/siyuan · error

download failed:

Error message

download failed: 

What it means

fetchBytes performs the actual GET with the shared httpclient; if the HTTP transport itself fails (connection error, DNS failure, TLS error, timeout), the underlying error text is wrapped in a fixed `download failed: ` prefix (note: no HTTP status here — status failures produce `download failed: HTTP <code>` instead).

Source

Thrown at kernel/util/skill.go:699

	// 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 8641553a1f)

Solutions

  1. Check network connectivity to the host in the URL (curl the download URL from the same machine)
  2. Fix proxy/TLS configuration for the environment (proxy env vars, trusted CA certs)
  3. Retry after transient failures; the error text (after the prefix) names the root cause
  4. Use an alternative source URL (mirror, self-hosted zip) reachable from the network

Example fix

// before
util.InstallSkill("https://internal.example.com/skill.zip") // connection refused on restricted network
// after
util.InstallSkill("https://codeload.github.com/owner/repo/zip/refs/heads/main") // reachable host
Defensive patterns

Strategy: retry

Validate before calling

// probe reachability before install
resp, err := http.Get("https://codeload.github.com")
if err != nil {
    return fmt.Errorf("network unreachable: %w", err)
}
resp.Body.Close()

Try / catch

if _, err := util.InstallSkill(src); err != nil {
    if strings.HasPrefix(err.Error(), "download failed: ") && !strings.Contains(err.Error(), "HTTP ") {
        // transport-level failure: retry with backoff, then report connectivity problem
    }
    return err
}

Prevention

When it happens

Trigger: Any InstallSkill download whose underlying http.Get errors: DNS resolution failure, connection refused/reset, TLS handshake failure, proxy misconfiguration, or request timeout — on codeload.github.com, raw.githubusercontent.com, or any custom direct URL.

Common situations: Offline or firewalled environments blocking github domains; corporate proxies without configured trust; DNS hijacking; IPv6 issues; transient network flaps during skill installation.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/ee97c8dc6c902620. Report an issue: GitHub.