siyuan-note/siyuan · error

invalid github URL: %s

Error message

invalid github URL: %s

What it means

Thrown by normalizeGitHubURL when a github.com URL path has fewer than two segments (i.e. lacks both owner and repo). The installer requires at least /owner/repo to build a codeload download URL; anything shorter is ambiguous.

Source

Thrown at kernel/util/skill.go:333

// codeloadSource 构造 codeload zip 下载源,branch 用于 main→master 回退
func codeloadSource(ownerRepo, branch string) normalizedSkillSource {
	return normalizedSkillSource{
		downloadURL: "https://codeload.github.com/" + ownerRepo + "/zip/refs/heads/" + branch,
		isZip:       true,
		branch:      branch,
	}
}

// normalizeGitHubURL 处理 github.com 的各种路径形态
func normalizeGitHubURL(u *url.URL) (normalizedSkillSource, error) {
	// /owner/repo/tree/<branch> 或 /owner/repo/tree/<branch>/<path>
	// /owner/repo/commit/<sha>
	// /owner/repo/releases/download/<tag>/<asset>
	// /owner/repo(默认分支)
	parts := strings.Split(strings.Trim(u.Path, "/"), "/")
	if len(parts) < 2 {
		return normalizedSkillSource{}, fmt.Errorf("invalid github URL: %s", u.String())
	}
	ownerRepo := parts[0] + "/" + parts[1]

	// releases/download/<tag>/<asset>
	if len(parts) >= 6 && parts[2] == "releases" && parts[3] == "download" {
		asset := parts[5]
		// 是否 zip 交由 Content-Type 最终判定,这里仅按 asset 后缀预判
		return normalizedSkillSource{downloadURL: u.String(), isZip: strings.HasSuffix(asset, ".zip")}, nil
	}

	// tree/<branch>[/path] 或 blob/<branch>/...
	if len(parts) >= 4 && (parts[2] == "tree" || parts[2] == "blob") {
		branch := parts[3]
		if parts[2] == "blob" {
			// blob 指向单个文件,走 raw
			rawPath := strings.Join(parts[4:], "/")
			return normalizedSkillSource{
				downloadURL: "https://raw.githubusercontent.com/" + ownerRepo + "/" + branch + "/" + rawPath,

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Provide a full repository URL such as https://github.com/owner/repo.
  2. If targeting a subdirectory, use the tree/<branch>/<path> form with at least owner/repo present.
  3. Validate the path has at least two segments client-side.

Example fix

// before
util.InstallSkill("https://github.com/owner")

// after
util.InstallSkill("https://github.com/owner/repo")
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(src)
if err == nil && u.Host == "github.com" {
    segs := strings.Split(strings.Trim(u.Path, "/"), "/")
    if len(segs) < 2 || segs[0] == "" || segs[1] == "" {
        return errors.New("github URL must include owner and repo")
    }
}

Prevention

When it happens

Trigger: Passing 'https://github.com/' or 'https://github.com/owner' (only one path segment); a URL whose path was stripped to empty by trimming.

Common situations: User copied a profile URL instead of a repository URL; trailing slash trimming collapsed the path; the URL is the GitHub root.

Related errors


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