sipeed/picoclaw · warning

skill name is required

Error message

skill name is required

What it means

skillsRemoveFromWorkspace requires a skill name; after strings.TrimSpace and stripping surrounding '/', the argument was empty. Pure argument validation that fires before any filesystem access, so nothing is deleted.

Source

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

func workspaceHasValidSkillDirectory(workspace, directory string) bool {
	loader := skills.NewSkillsLoader(workspace, "", "")
	for _, skill := range loader.ListSkills() {
		if skill.Source != "workspace" {
			continue
		}
		if filepath.Base(filepath.Dir(skill.Path)) == directory {
			return true
		}
	}
	return false
}

func skillsRemoveFromWorkspace(workspace string, toolsConfig config.SkillsToolsConfig, skillName string) error {
	name := strings.TrimSpace(skillName)
	name = strings.Trim(name, "/")
	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)
	}

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Pass the skill name: `picoclaw skills remove <name>`.
  2. List installed skills first (`picoclaw skills list`) to get exact names.
  3. In scripts, skip the call when the variable is empty or unset.

Example fix

# before
picoclaw skills remove "$SKILL"   # SKILL is unset -> ""
# after
picoclaw skills remove myskill
Defensive patterns

Strategy: validation

Validate before calling

name := strings.Trim(strings.TrimSpace(skillName), "/")
if name == "" {
    return fmt.Errorf("skill name is required")
}

Type guard

func hasSkillName(s string) bool {
    return strings.Trim(strings.TrimSpace(s), "/") != ""
}

Prevention

When it happens

Trigger: Running `skills remove` with no argument, an empty string, " ", or "/" — name is empty after the trims at helpers.go:160.

Common situations: Forgetting the argument, a shell variable that expands to empty ($SKILL unset), or a script looping over an empty list.

Related errors


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