sipeed/picoclaw · error

failed to remove skill '%s': %w

Error message

failed to remove skill '%s': %w

What it means

os.RemoveAll on <workspace>/skills/<name> returned a non-nil error, wrapped with the skill name and the underlying cause. This is an OS-level failure during deletion (permissions, read-only filesystem, open file handles), not a validation problem — the directory existed but could not be removed.

Source

Thrown at cmd/picoclaw/internal/skills/helpers.go:177

	if name == "" {
		return fmt.Errorf("skill name is required")
	}
	if strings.Contains(name, "/") {
		dirName, err := skills.GitHubInstallDirNameFromToolsConfig(toolsConfig, name)
		if err != nil || dirName == "" {
			return fmt.Errorf("invalid skill name %q", skillName)
		}
		name = dirName
	}
	if name == "." || name == ".." {
		return fmt.Errorf("invalid skill name %q", skillName)
	}
	skillDir := filepath.Join(workspace, "skills", name)
	if _, err := os.Stat(skillDir); os.IsNotExist(err) {
		return fmt.Errorf("skill '%s' not found", name)
	}
	if err := os.RemoveAll(skillDir); err != nil {
		return fmt.Errorf("failed to remove skill '%s': %w", name, err)
	}
	return nil
}

func skillsInstallBuiltinCmd(workspace string) {
	builtinSkillsDir := "./picoclaw/skills"
	workspaceSkillsDir := filepath.Join(workspace, "skills")

	fmt.Printf("Copying builtin skills to workspace...\n")

	skillsToInstall := []string{
		"weather",
		"news",
		"stock",
		"calculator",
	}

	for _, skillName := range skillsToInstall {

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Inspect the wrapped %w cause: EACCES/EPERM means permissions, EROFS means read-only mount
  2. Fix ownership/permissions on the skill directory (e.g. chown -R or chmod -R u+w <workspace>/skills/<name>) and retry
  3. Close editors/IDEs/indexers that may hold files inside the skill directory, then retry
  4. On Windows, retry after stopping antivirus/indexing locks or reboot if a handle is stuck

Example fix

# inspect the cause
picoclaw skills remove weather
# -> failed to remove skill 'weather': ... permission denied

# fix and retry
chmod -R u+w ~/.picoclaw/skills/weather && picoclaw skills remove weather
Defensive patterns

Strategy: retry

Validate before calling

func canRemove(dir string) bool {
    info, err := os.Stat(dir)
    return err == nil && info.IsDir() && info.Mode().Perm()&0200 != 0
}

Try / catch

err := skillsRemoveFromWorkspace(ws, cfg, name)
if err != nil {
    if strings.Contains(err.Error(), "failed to remove skill") {
        // inspect errors.Unwrap(err) for EACCES/EROFS; remediate perms or close locks, then retry once
    }
}

Prevention

When it happens

Trigger: Removing a skill whose directory contains files the process cannot write/delete (ownership mismatch, mode bits), a read-only or full disk mount, or (on Windows) a file inside the skill dir held open by an editor, indexer, or antivirus.

Common situations: Workspace created by root/admin but CLI run as a normal user; workspace on a network or read-only mount; a file watcher or IDE holding SKILL.md open; NFS stale-handle errors.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/1522709601aa6328. Report an issue: GitHub.