siyuan-note/siyuan · error
skill path is not a regular file or directory
Error message
skill path is not a regular file or directory
What it means
checkManagedSkillPath validates each ancestor component of a managed-skill path under data/storage/ai/agent/skills. This error means an existing path component is neither a symlink-free directory nor a regular file (e.g. a symlink, FIFO, device or socket), so skill file operations refuse to touch it. The library enforces this to prevent link redirection and special-file side effects inside the skill storage root.
Solutions
- Inspect the reported path under data/storage/ai/agent/skills with ls -l (or equivalent) and delete or replace the symlink/special file with a real directory or file
- Copy the actual skill content into a real directory instead of linking it
- Re-run the skill management operation after the path contains only regular files and directories
Example fix
// before (shell, in workspace) ln -s ~/shared-skills/my-skill data/storage/ai/agent/skills/my-skill // after cp -r ~/shared-skills/my-skill data/storage/ai/agent/skills/my-skill
Defensive patterns
Strategy: validation
Validate before calling
func pathIsClean(root *os.Root, p string) error {
info, err := root.Lstat(p)
if err != nil { return err }
if info.Mode()&os.ModeSymlink != 0 || (!info.IsDir() && !info.Mode().IsRegular()) {
return errors.New("symlink or special file at " + p)
}
return nil
} Type guard
func isRegularOrDir(info os.FileInfo) bool {
return info.Mode()&os.ModeSymlink == 0 && (info.IsDir() || info.Mode().IsRegular())
} Try / catch
if err := ManageSkillFiles(req); err != nil && strings.Contains(err.Error(), "not a regular file or directory") {
// surface guidance: remove symlinks/special files from skill storage
} Prevention
- Never symlink into data/storage/ai/agent/skills; copy content instead
- Audit skill storage after syncing between machines or platforms for links/junctions
- Keep IPC artifacts like FIFOs and sockets out of the workspace data directory
When it happens
Trigger: Any ManageSkillFiles action (list/read/write/create/mkdir/move/remove) whose request.Path, Target, or an intermediate path component resolves to a symlink or special file (non-regular, non-directory) via root.Lstat during checkManagedSkillPath; also re-checked after writeManagedSkillSource writes the temp file, so the target being swapped to a link mid-operation also raises it.
Common situations: A user manually created symlinks inside storage/ai/agent/skills to share skills between workspaces; a synced/copied directory contains macOS Finder aliases or Windows junction points; a leftover FIFO or socket from another tool occupies a skill name.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- asset path resolves outside notebook assets directory
- skill directory contains a link or special file
- symlink escapes workspace
- template path is not a regular file or directory
- access to sensitive workspace file is forbidden
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/6bef9726a7261eb0.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/util/skill_manage.go:116
}
return workspace.OpenRoot("storage/ai/agent/skills")
}
func checkManagedSkillPath(root *os.Root, p string) error {
if err := validateManagedSkillPath(p); err != nil {
return err
}
parts := strings.Split(p, "/")
for i := range parts {
info, err := root.Lstat(strings.Join(parts[:i+1], "/"))
if errors.Is(err, os.ErrNotExist) && i == len(parts)-1 {
return nil
}
if err != nil {
return err
}
if info.Mode()&os.ModeSymlink != 0 || (!info.IsDir() && !info.Mode().IsRegular()) {
return errors.New("skill path is not a regular file or directory")
}
}
return nil
}
func isManagedSkillManifest(p string) bool {
return strings.Count(p, "/") == 1 && strings.EqualFold(path.Base(p), "SKILL.md")
}
// 目录版本包含每个资源的内容哈希,保持大小和修改时间不变的外部编辑也会产生冲突。
func managedSkillRevision(root *os.Root, p string) (string, error) {
h := sha256.New()
err := fs.WalkDir(root.FS(), p, func(name string, entry fs.DirEntry, walkErr error) error {
if walkErr != nil {
return walkErr
}
info, err := entry.Info()
if err != nil {View on GitHub (pinned to 9f775e8a12)