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
- Inspect the skill's published archive layout on the registry and compare it with an installable skill.
- Report the packaging problem to the skill author or registry.
- Try a different version — packaging regressions are common between releases.
- 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
- Publish skills from a template matching the loader's expected layout.
- Run test installs in CI for skills you publish.
- Pin versions whose packaging is known to install cleanly.
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
- ✗ invalid install target %q: %w
- ✗ invalid registry name: %w
- ✗ failed to install skill: %w
- ✗ Skill '%s' is flagged as malicious and cannot be installed
- no models available
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/2b7272c2f48b4dbb.
Report an issue: GitHub.