siyuan-note/siyuan · error
invalid download URL: %s
Error message
invalid download URL: %s
What it means
Thrown by downloadSkillSource when the already-normalized download URL fails url.Parse or has an empty host. This is a defensive check on an internally-constructed URL; reaching it usually indicates a bug in normalizeSkillURL/normalizeGitHubURL producing a malformed downloadURL.
Source
Thrown at kernel/util/skill.go:374
// commit/<sha>
if len(parts) >= 4 && parts[2] == "commit" {
sha := parts[3]
return normalizedSkillSource{
downloadURL: "https://codeload.github.com/" + ownerRepo + "/zip/" + sha,
isZip: true,
}, nil
}
// 纯仓库地址:默认 main,失败回退 master
return codeloadSource(ownerRepo, "main"), nil
}
// downloadSkillSource 下载 skill 源,返回字节、Content-Type
func downloadSkillSource(src normalizedSkillSource) (data []byte, contentType string, err error) {
u, perr := url.Parse(src.downloadURL)
if perr != nil || u.Host == "" {
return nil, "", fmt.Errorf("invalid download URL: %s", src.downloadURL)
}
if cerr := CheckHostSSRF(u.Hostname()); cerr != nil {
return nil, "", cerr
}
data, contentType, err = fetchBytes(src.downloadURL)
if err == nil {
return data, contentType, nil
}
// 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)View on GitHub (pinned to 251596fc0d)
Solutions
- Inspect the normalizedSkillSource.downloadURL produced by normalizeSkillURL for the given input.
- Ensure normalizeGitHubURL always returns a populated downloadURL for every accepted branch.
- Report the input that triggered it so the normalization gap can be fixed upstream.
Defensive patterns
Strategy: try-catch
Try / catch
// defensive: surface the malformed internal URL for diagnosis
res, err := util.InstallSkill(src)
if err != nil && strings.HasPrefix(err.Error(), "invalid download URL") {
logging.LogErrorf("normalizeSkillURL produced a bad downloadURL for input %q", src)
} Prevention
- Report the exact input that triggers this so the normalization logic can be patched.
- Treat this error as an internal bug, not a user mistake.
- Add unit tests covering each normalizeGitHubURL branch to prevent regressions.
When it happens
Trigger: A code path constructs a normalizedSkillSource with an empty or malformed downloadURL (e.g. a codeload URL built from an empty ownerRepo); the SSRF/host check then cannot proceed. Not typically reachable from valid user input.
Common situations: A future refactor breaks URL construction; an unexpected branch in normalizeGitHubURL returns an empty downloadURL; a custom (non-github) host produced a URL without a host component.
Related errors
- unsupported skill source (content-type: %s); expected a zip
- download failed (tried main and master): %v
- download failed: %s
- download failed: HTTP %d
- read body failed: %s
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/def7cdf7e9534927.
Report an issue: GitHub.