siyuan-note/siyuan · error
unrecognized skill source
Error message
unrecognized skill source: %s
What it means
normalizeSkillURL accepts owner/repo shorthand, bare owner/repo-like inputs, and full URLs with a scheme and host. If the input cannot be parsed as a URL with both scheme and host (and did not match earlier shorthand patterns), it is rejected as 'unrecognized skill source: %s'.
Solutions
- Use the owner/repo shorthand form (e.g. 'owner/repo') for GitHub repos
- Prefix URLs with the full scheme: 'https://github.com/...' or 'https://raw.githubusercontent.com/...'
- Trim whitespace/newlines from pasted input before calling
- Verify the string parses as an absolute URL with scheme and host
Example fix
// before
InstallSkill("github.com/owner/repo") // no scheme, not shorthand
// after
InstallSkill("owner/repo")
// or
InstallSkill("https://github.com/owner/repo") Defensive patterns
Strategy: validation
Validate before calling
function looksLikeSkillSource(s) {
if (/^[\w.-]+\/[\w.-]+$/.test(s)) return true; // owner/repo
try { const u = new URL(s); return !!u.host; } catch { return false; }
} Try / catch
try {
await installSkill(raw);
} catch (e) {
if (String(e.message).startsWith("unrecognized skill source")) {
// normalize input: add https:// scheme or use owner/repo shorthand
}
} Prevention
- Use owner/repo shorthand for GitHub repos
- Always include https:// for full URLs
- Trim whitespace/newlines from pasted input
- Validate the URL parses with scheme and host before calling
When it happens
Trigger: Passing a string that is neither owner/repo shorthand nor an absolute http(s) URL — e.g. 'my folder/skill', 'ftp:thing', 'github.com/owner/repo' without scheme (depending on shorthand matching), or a malformed URL like 'http://'.
Common situations: Copy-pasting a partial path or local directory path instead of a repo/URL; omitting the https:// scheme; trailing spaces or newline in pasted input; non-Git URLs the normalizer does not recognize.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- CalDAV: calendar object path is invalid
- CalDAV: calendar path is invalid
- CardDAV: address book path is invalid
- CardDAV: path is invalid
- data?.msg || data?.message ||…
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/0389996b8091dbfa.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/util/skill.go:603
func normalizeSkillURL(raw string) (normalizedSkillSource, error) {
raw = strings.TrimSpace(raw)
// 1. 整条 "npx skills add owner/repo ..." 命令:提取 owner/repo
if strings.Contains(raw, "skills add") || strings.Contains(raw, "skills@") {
if m := skillsAddPattern.FindStringSubmatch(raw); len(m) == 2 {
return codeloadSource(m[1], "main"), nil
}
}
// 2. owner/repo 简写(无 scheme、无点、单个 /)
if !strings.Contains(raw, "://") && !strings.Contains(raw, "//") && ownerRepoPattern.MatchString(raw) {
return codeloadSource(raw, "main"), nil
}
// 3. 带 scheme 的 URL
u, err := url.Parse(raw)
if err != nil || u.Scheme == "" || u.Host == "" {
return normalizedSkillSource{}, fmt.Errorf("unrecognized skill source: %s", raw)
}
switch u.Host {
case "github.com":
return normalizeGitHubURL(u)
case "raw.githubusercontent.com":
// 直接 GET 单个 SKILL.md(或其它文本文件)
return normalizedSkillSource{downloadURL: u.String()}, nil
default:
// 其它直链(release zip、自建站点等):直接 GET,是否 zip 交由 Content-Type 判定
return normalizedSkillSource{downloadURL: u.String()}, nil
}
}
// codeloadSource 构造 codeload zip 下载源,branch 用于 main→master 回退
func codeloadSource(ownerRepo, branch string) normalizedSkillSource {
return normalizedSkillSource{
downloadURL: "https://codeload.github.com/" + ownerRepo + "/zip/refs/heads/" + branch,View on GitHub (pinned to 9f775e8a12)