sipeed/picoclaw · error

✗ failed to install skill: registry archive for %q is not a

Error message

✗ failed to install skill: registry archive for %q is not a valid skill

What it means

The download and extraction succeeded, but post-install validation failed: workspaceHasValidSkillDirectory re-scans the workspace with the skills loader and found no workspace-sourced skill whose directory base name matches dirName. That means the archive's layout does not produce a discoverable, correctly named skill directory; the partial install is deleted.

Source

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

		return fmt.Errorf("✗ failed to install skill: %w", err)
	}

	if result.IsMalwareBlocked {
		rmErr := os.RemoveAll(targetDir)
		if rmErr != nil {
			fmt.Printf("\u2717 Failed to remove partial install: %v\n", rmErr)
		}

		return fmt.Errorf("\u2717 Skill '%s' is flagged as malicious and cannot be installed.\n", target)
	}

	if result.IsSuspicious {
		fmt.Printf("\u26a0\ufe0f  Warning: skill '%s' is flagged as suspicious.\n", target)
	}

	if !workspaceHasValidSkillDirectory(workspace, dirName) {
		_ = os.RemoveAll(targetDir)
		return fmt.Errorf("✗ failed to install skill: registry archive for %q is not a valid skill", target)
	}

	normalizedSlug, registryURL := skills.BuildInstallMetadataForRegistryInstance(registry, target, result.Version)
	installedAt := time.Now().UnixMilli()
	if err := writeInstalledSkillOriginMeta(targetDir, installedSkillOriginMeta{
		Version:          1,
		OriginKind:       "third_party",
		Registry:         registry.Name(),
		Slug:             normalizedSlug,
		RegistryURL:      registryURL,
		InstalledVersion: result.Version,
		InstalledAt:      installedAt,
	}); err != nil {
		_ = os.RemoveAll(targetDir)
		return fmt.Errorf("✗ failed to persist skill metadata: %w", err)
	}

	fmt.Printf("\u2713 Skill '%s' v%s installed successfully!\n", dirName, result.Version)

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Inspect the skill's published archive layout on the registry and compare it with an installable skill.
  2. Report the packaging problem to the skill author or registry.
  3. Try a different version — packaging regressions are common between releases.
  4. If you own the skill, package it so its files sit in a single root directory the loader can discover (matching dirName).
Defensive patterns

Strategy: validation

Type guard

func archiveLooksLikeSkill(extractDir, dirName string) bool {
    loader := skills.NewSkillsLoader(filepath.Dir(extractDir), "", "")
    for _, s := range loader.ListSkills() {
        if s.Source == "workspace" && filepath.Base(filepath.Dir(s.Path)) == dirName {
            return true
        }
    }
    return false
}

Try / catch

if err != nil && strings.Contains(err.Error(), "not a valid skill") {
    // archive layout mismatch — report to the registry; do not retry the same version
    return reportPackagingIssue(target, result.Version)
}

Prevention

When it happens

Trigger: An archive that extracts into an unexpected layout — everything nested under an extra top-level folder, a root directory name that does not match dirName, or missing the files the SkillsLoader needs to recognize a skill — fails the check at helpers.go:109 (see workspaceHasValidSkillDirectory, helpers.go:143).

Common situations: Registry packaging bug, a zip built with a different root folder name, or a repo published as a skill without the manifest/layout picoclaw's loader expects.

Related errors


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