siyuan-note/siyuan · warning
skill source is required
Error message
skill source is required
What it means
Thrown by InstallSkill at the very top when rawURL is empty after trimming whitespace. It is the precondition guard ensuring a non-empty source string before any URL normalization or network call. Pure input validation, no I/O involved.
Source
Thrown at kernel/util/skill.go:253
var ownerRepoPattern = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9._-]*/[A-Za-z0-9][A-Za-z0-9._-]*$`)
// skillsAddPattern 从 "npx skills add owner/repo ..." 这类命令里提取 owner/repo
var skillsAddPattern = regexp.MustCompile(`(?:^|\s)([A-Za-z0-9][A-Za-z0-9._-]*/[A-Za-z0-9][A-Za-z0-9._-]*)(?:\s|$)`)
// normalizedSkillSource 描述归一化后的下载源
type normalizedSkillSource struct {
downloadURL string // 实际 GET 的地址
isZip bool // 是否按 zip 解压处理(codeload / release zip / Content-Type 判定为 zip)
branch string // codeload 分支,空表示无需回退;main 失败回退 master
}
// InstallSkill 从 GitHub 仓库或直链下载并安装 skill 到 SkillsDir()。
// 支持的输入:owner/repo 简写、整条 "npx skills add owner/repo -g" 命令、
// 完整 GitHub 仓库/子目录/commit URL、raw SKILL.md 直链、release zip 直链。
func InstallSkill(rawURL string) (*InstallSkillResult, error) {
rawURL = strings.TrimSpace(rawURL)
if rawURL == "" {
return nil, errors.New("skill source is required")
}
src, err := normalizeSkillURL(rawURL)
if err != nil {
return nil, err
}
data, contentType, err := downloadSkillSource(src)
if err != nil {
return nil, err
}
// 按内容类型或来源判定处理方式
isZip := src.isZip || strings.HasPrefix(contentType, "application/zip") ||
strings.HasPrefix(contentType, "application/x-zip-compressed")
if isZip {
return installFromZip(data)View on GitHub (pinned to 251596fc0d)
Solutions
- Validate non-empty input in the API/UI handler before calling InstallSkill and return a clear field error.
- Trim and check the string client-side; disable the install button when empty.
- Default to a documented example URL in test scaffolding rather than an empty string.
Example fix
// before
res, err := util.InstallSkill(strings.TrimSpace(input))
// after
src := strings.TrimSpace(input)
if src == "" {
return errors.New("please provide a skill source URL or owner/repo")
}
res, err := util.InstallSkill(src) Defensive patterns
Strategy: validation
Validate before calling
src := strings.TrimSpace(rawURL)
if src == "" {
return errors.New("a skill source URL or owner/repo is required")
} Prevention
- Disable the install action in the UI when the input is blank.
- Trim and validate input in the API handler before forwarding to InstallSkill.
- Provide a placeholder/example so users know the expected format.
When it happens
Trigger: Calling InstallSkill with an empty string, only whitespace, or a value that became empty after TrimSpace. Typically an API handler or UI that forwarded an unvalidated empty field.
Common situations: The install dialog was submitted without a URL; a programmatic caller passed a zero-value string; an upstream trim already cleared the field but the caller did not short-circuit.
Related errors
- unrecognized skill source: %s
- Activation code cannot be empty
- invalid notebook ID
- OIDC claim rule values cannot be empty
- Conf.Language(142)
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/257c6a1f1d9c060a.
Report an issue: GitHub.