{"record":{"id":"5b008bafef037151","repo":"siyuan-note/siyuan","slug":"skill-directory-already-exists-or-is-invalid","errorCode":null,"errorMessage":"skill directory already exists or is invalid","messagePattern":"skill directory already exists or is invalid","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/skill_manage.go","lineNumber":333,"sourceCode":"\t\t\t\t\t_, err = readManagedSkillSource(root, p)\n\t\t\t\t\teditable = err == nil\n\t\t\t\t}\n\t\t\t}\n\t\t\tret.Entries = append(ret.Entries, SkillFileEntry{Path: p, IsDir: entry.IsDir(), Editable: editable})\n\t\t\treturn nil\n\t\t})\n\t\treturn ret, err\n\t}\n\tif err = checkManagedSkillPath(root, request.Path); err != nil {\n\t\treturn ret, err\n\t}\n\tabs := filepath.Join(root.Name(), filepath.FromSlash(request.Path))\n\tfilelock.Lock(abs)\n\tdefer filelock.Unlock(abs)\n\tinfo, statErr := root.Lstat(request.Path)\n\tif request.Action == \"create\" {\n\t\tif strings.Contains(request.Path, \"/\") || !errors.Is(statErr, os.ErrNotExist) {\n\t\t\treturn ret, errors.New(\"skill directory already exists or is invalid\")\n\t\t}\n\t\tcontent := request.Content\n\t\tif content == \"\" {\n\t\t\tcontent = \"---\\nname: \" + request.Path + \"\\ndescription: \\n---\\n\\n\"\n\t\t}\n\t\ttmp := \".skill-\" + ast.NewNodeID()\n\t\tif err = root.Mkdir(tmp, 0755); err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\tdefer root.RemoveAll(tmp)\n\t\tif err = writeManagedSkillSource(root, path.Join(tmp, \"SKILL.md\"), content, true, \"\"); err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\tif err = root.Rename(tmp, request.Path); err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\tret.Content = &content\n\t\tret.Revision = fmt.Sprintf(\"%x\", sha256.Sum256([]byte(content)))","sourceCodeStart":315,"sourceCodeEnd":351,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/util/skill_manage.go#L315-L351","documentation":"The \"create\" action makes a new top-level skill directory containing a SKILL.md manifest. This error is returned when the requested path already exists (Lstat finds anything, including a directory, file, or link) or when the path contains \"/\", since only top-level skill names can be created this way (subdirectories are made with \"mkdir\").","triggerScenarios":"ManageSkillFiles{Action:\"create\"} where request.Path contains a slash (e.g. \"my-skill/sub\"), or root.Lstat(request.Path) returns success — the skill already exists (possibly as a leftover directory).","commonSituations":"Re-running an idempotent setup script that creates skills on every run; trying to create nested paths with \"create\" instead of creating the skill first and using \"mkdir\"; a skill with the same name left behind after a failed delete.","solutions":["Check existence first (action \"read\" or \"list\") and use \"write\"/\"mkdir\" to modify the existing skill instead of \"create\"","Pick a different skill name","Remove the leftover directory before re-creating","Use \"mkdir\" for subdirectory creation after the skill exists"],"exampleFix":"// before\nManageSkillFiles(SkillFileRequest{Action: \"create\", Path: \"my-skill/docs\"})\n// after\nManageSkillFiles(SkillFileRequest{Action: \"create\", Path: \"my-skill\"})\nManageSkillFiles(SkillFileRequest{Action: \"mkdir\", Path: \"my-skill/docs\"})","handlingStrategy":"validation","validationCode":"_, err := ManageSkillFiles(SkillFileRequest{Action: \"read\", Path: name})\nif err == nil { // skill already exists — write or pick another name\n}\nif strings.Contains(name, \"/\") { // use create for top-level names only\n}","typeGuard":"func canCreateSkill(name string) bool { return name != \"\" && !strings.Contains(name, \"/\") }","tryCatchPattern":"if err := ManageSkillFiles(createReq); err != nil && strings.Contains(err.Error(), \"already exists or is invalid\") {\n  // fall back to read + write, or choose a new name\n}","preventionTips":["List skills before creating to detect name collisions","Use create only for top-level names; use mkdir for subdirectories","Make creation flows idempotent (check-then-create)"],"tags":["filesystem","already-exists","skills"],"backgroundTag":"file-already-exists","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}