siyuan-note/siyuan · error

skill source is required

Error message

skill source is required

What it means

InstallSkill downloads and installs a skill from a GitHub repo, raw SKILL.md link, or release zip. It rejects an empty/whitespace-only source string with 'skill source is required' before any URL normalization is attempted.

Solutions

  1. Provide a non-empty source: an owner/repo shorthand, a GitHub URL, or a raw SKILL.md/zip URL
  2. Validate the input is non-empty in the UI/form before invoking the install
  3. Check that the config value supplying the source is populated

Example fix

// before
InstallSkill(cfg.SkillSource) // may be ""
// after
if strings.TrimSpace(cfg.SkillSource) == "" {
    return errors.New("skill source must be set")
}
result, err := InstallSkill(cfg.SkillSource)
Defensive patterns

Strategy: validation

Validate before calling

const source = (input ?? "").trim();
if (!source) throw new Error("skill source is required");

Try / catch

if (!input || !input.trim()) {
  return { ok: false, reason: "empty skill source" };
}
try {
  await installSkill(input);
} catch (e) {
  if (String(e.message) === "skill source is required") {
    // prompt the user for a source
  }
}

Prevention

When it happens

Trigger: Calling InstallSkill("") or InstallSkill(" ") — a blank source string after TrimSpace.

Common situations: Empty input field in the install dialog; variable not assigned before the call; config value for skill source missing or blank; form submitted without filling the source.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/257c6a1f1d9c060a. Report an issue: GitHub.

Appendix: source

Thrown at kernel/util/skill.go:555

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 9f775e8a12)