siyuan-note/siyuan · error

skill destination already exists or is inaccessible

Error message

skill destination already exists or is inaccessible

What it means

The 'move' action refuses to run when the destination path already exists or cannot be stat-ed. Lstat on the target must return os.ErrNotExist; any other outcome (existing file, existing directory, or an access error) aborts the rename to prevent silent overwrites.

Solutions

  1. Choose a Target name that does not exist in the source directory
  2. Remove or move away the existing file at the target first
  3. Fix filesystem permissions on the parent directory so Lstat can report ErrNotExist
  4. Verify the target with Lstat before calling move

Example fix

// before
{Action: "move", Path: "skills/foo/SKILL.md", Target: "skills/foo/README.md"} // exists
// after
{Action: "move", Path: "skills/foo/SKILL.md", Target: "skills/foo/SKILL-v2.md"}
Defensive patterns

Strategy: validation

Validate before calling

if _, err := root.Lstat(target); !errors.Is(err, os.ErrNotExist) { /* pick another name or clear the target */ }

Try / catch

if err := ManageSkillFiles(req); err != nil { if strings.Contains(err.Error(), "destination already exists") { /* retry with a unique name */ } }

Prevention

When it happens

Trigger: Calling ManageSkillFiles with request.Action == "move" where root.Lstat(request.Target) returns nil (target exists) or an error other than os.ErrNotExist (e.g. permission denied on the parent dir).

Common situations: Renaming a skill to a name that already exists; a stale leftover file at the target; a target directory that is unreadable/unsearchable so Lstat fails.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


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

Appendix: source

Thrown at kernel/util/skill_manage.go:419

	switch request.Action {
	case "write":
		if info != nil && info.IsDir() {
			return ret, errors.New("cannot write a skill directory")
		}
		if err = writeManagedSkillSource(root, request.Path, request.Content, info == nil, request.Revision); err != nil {
			return ret, err
		}
		ret.Revision = fmt.Sprintf("%x", sha256.Sum256([]byte(request.Content)))
		return ret, nil
	case "move":
		if err = checkManagedSkillPath(root, request.Target); err != nil {
			return ret, err
		}
		if path.Dir(request.Path) != path.Dir(request.Target) {
			return ret, errors.New("skills and text files can only be renamed in the same directory")
		}
		if _, err = root.Lstat(request.Target); !errors.Is(err, os.ErrNotExist) {
			return ret, errors.New("skill destination already exists or is inaccessible")
		}
		return ret, root.Rename(request.Path, request.Target)
	case "remove":
		if info.IsDir() {
			return ret, root.RemoveAll(request.Path)
		}
		return ret, root.Remove(request.Path)
	}
	return ret, errors.New("unsupported skill operation")
}

View on GitHub (pinned to 9f775e8a12)