siyuan-note/siyuan · error
no valid skill installed
Error message
no valid skill installed
What it means
Thrown by installSkillDirs when every candidate skill in the archive was skipped, leaving zero installed. Skips happen when SKILL.md cannot be read, the frontmatter lacks 'name' (root case), or the name fails validation. The loop logs each skip but ultimately fails the install.
Source
Thrown at kernel/util/skill.go:542
if err := os.MkdirAll(SkillsDir(), 0755); err != nil {
return nil, err
}
// 覆盖式安装:先清旧目录
if gulu.File.IsExist(destDir) {
os.RemoveAll(destDir)
}
if err := filelock.Copy(srcDir, destDir); err != nil {
return nil, fmt.Errorf("install skill %s failed: %s", name, err)
}
result.Names = append(result.Names, name)
desc := fm["description"]
if desc == "" {
desc = firstLine(body)
}
result.Descriptions = append(result.Descriptions, desc)
}
if len(result.Names) == 0 {
return nil, errors.New("no valid skill installed")
}
return result, nil
}
// installFromSingleSkillMD 把单个 SKILL.md 文本内容落地为一个 skill
func installFromSingleSkillMD(data []byte) (*InstallSkillResult, error) {
content := string(data)
fm, body := parseSkillFrontmatter(content)
name := fm["name"]
if name == "" {
return nil, errors.New("SKILL.md frontmatter missing 'name' field")
}
if err := validateSkillName(name); err != nil {
return nil, err
}
if err := SaveSkill(name, content); err != nil {
return nil, err
}View on GitHub (pinned to 251596fc0d)
Solutions
- Add a 'name:' field to the frontmatter of each SKILL.md, especially any at the archive root.
- Place each skill in a named subdirectory so the directory name can backstop a missing frontmatter name.
- Ensure skill names pass validateSkillName (no slashes, traversal, or '.'/'..' literals).
Example fix
// before — SKILL.md at archive root with no name --- description: a skill --- ... // after — add the name field --- name: my-skill description: a skill --- ...
Defensive patterns
Strategy: validation
Validate before calling
// validate each SKILL.md in the source has a usable name before packaging
for _, md := range skillFiles {
fm, _ := parseFrontmatter(md)
if fm["name"] == "" && !hasParentDir(md) {
return errors.New("root SKILL.md must declare a 'name' frontmatter field")
}
} Prevention
- Always include a 'name:' field in SKILL.md frontmatter.
- Put each skill in its own named subdirectory so the directory name can backstop a missing name.
- Avoid names containing slashes or path traversal characters.
When it happens
Trigger: An archive whose only SKILL.md sits at the root with no 'name' frontmatter (skipped because the root temp dir name cannot be used); all skills have invalid names (slashes, traversal); SKILL.md files are unreadable.
Common situations: A root-level SKILL.md missing the 'name:' field; skill directories named with characters validateSkillName rejects; permission errors reading all SKILL.md files in the zip.
Related errors
- no SKILL.md found in the archive
- marketplace package manifest must be at the archive root or
- unzip failed: %s
- SKILL.md frontmatter missing 'name' field
- marketplace package manifest not found or invalid
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/0ef05f07f68da7b1.
Report an issue: GitHub.