sipeed/picoclaw · error
✗ invalid install target %q: %w
Error message
✗ invalid install target %q: %w
What it means
The install target (the part after the registry name) was rejected by registry.ResolveInstallDirName, which normalizes a slug or owner/repo form into an on-disk directory name under <workspace>/skills. Empty, malformed, or unmappable targets fail here, before any download starts.
Source
Thrown at cmd/picoclaw/internal/skills/helpers.go:66
}
// skillsInstallFromRegistry installs a skill from a named registry (e.g. clawhub).
func skillsInstallFromRegistry(cfg *config.Config, registryName, target string) error {
err := utils.ValidateSkillIdentifier(registryName)
if err != nil {
return fmt.Errorf("✗ invalid registry name: %w", err)
}
registryMgr := skills.NewRegistryManagerFromToolsConfig(cfg.Tools.Skills)
registry := registryMgr.GetRegistry(registryName)
if registry == nil {
return fmt.Errorf("✗ registry '%s' not found or not enabled. check your config.json.", registryName)
}
dirName, err := registry.ResolveInstallDirName(target)
if err != nil {
return fmt.Errorf("✗ invalid install target %q: %w", target, err)
}
fmt.Printf("Installing skill '%s' from %s registry...\n", target, registryName)
workspace := cfg.WorkspacePath()
targetDir := filepath.Join(workspace, "skills", dirName)
if _, err = os.Stat(targetDir); err == nil {
return fmt.Errorf("\u2717 skill '%s' already installed at %s", dirName, targetDir)
}
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
if err = os.MkdirAll(filepath.Join(workspace, "skills"), 0o755); err != nil {
return fmt.Errorf("\u2717 failed to create skills directory: %w", err)
}
View on GitHub (pinned to 49183d7e8d)
Solutions
- Use the exact target form the registry expects (slug or owner/repo) per its docs.
- Strip trailing slashes and stray quotes.
- Read the wrapped error for the specific rule broken.
- Confirm the target exists on the registry before installing.
Example fix
# before picoclaw skills install clawhub/owner/ # after picoclaw skills install clawhub/owner/repo
Defensive patterns
Strategy: validation
Validate before calling
target = strings.Trim(target, "/")
if _, err := registry.ResolveInstallDirName(target); err != nil {
return fmt.Errorf("invalid install target %q: %w", target, err)
} Type guard
func validInstallTarget(r skills.Registry, t string) bool {
_, err := r.ResolveInstallDirName(t)
return err == nil
} Prevention
- Trim trailing slashes and reject empty path segments before calling install.
- Document the target syntax (slug vs owner/repo) in command help.
- Validate against the same rules the registry uses when building install scripts.
When it happens
Trigger: Targets like "owner/" (empty repo), "/repo" (empty owner), strings with unexpected path separators or invalid characters, or anything ResolveInstallDirName cannot map — helpers.go:66.
Common situations: Copy-pasting a URL fragment instead of the slug, a trailing slash left by shell tab-completion, or a registry whose expected target syntax differs from what was typed.
Related errors
- ✗ invalid registry name: %w
- ✗ failed to install skill: registry archive for %q is not a
- ✗ registry '%s' not found or not enabled. check your config
- ✗ skill '%s' already installed at %s
- ✗ failed to install skill: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/e0ce79a125a136bb.
Report an issue: GitHub.