sipeed/picoclaw · error

✗ registry '%s' not found or not enabled. check your config

Error message

✗  registry '%s' not found or not enabled. check your config.json.

What it means

The registry name is syntactically valid but no enabled registry with that name exists in the loaded config: RegistryManager.GetRegistry returned nil. The message points at config.json because that is where registries (e.g. clawhub) are declared and enabled under tools.skills.

Source

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

		fmt.Printf("  ✓ %s (%s)\n", skill.Name, skill.Source)
		if skill.Description != "" {
			fmt.Printf("    %s\n", skill.Description)
		}
	}
}

// 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()

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. List the registries in the loaded config.json and use the exact key.
  2. Add or enable the registry entry (e.g. clawhub) under tools.skills.
  3. Check spelling and casing of the registry name.
  4. Confirm which config file picoclaw actually loads (global vs workspace) before editing.

Example fix

// before: tools.skills has no clawhub entry
// after:  { "tools": { "skills": { "registries": { "clawhub": { "enabled": true } } } } }
Defensive patterns

Strategy: validation

Validate before calling

mgr := skills.NewRegistryManagerFromToolsConfig(cfg.Tools.Skills)
if mgr.GetRegistry(registryName) == nil {
    return fmt.Errorf("registry %q not found or not enabled", registryName)
}

Type guard

func registryEnabled(mgr *skills.RegistryManager, name string) bool {
    return mgr.GetRegistry(name) != nil
}

Prevention

When it happens

Trigger: skillsInstallFromRegistry with a name that is not among cfg.Tools.Skills registries, or one that exists but is disabled — GetRegistry returns nil at helpers.go:61.

Common situations: Fresh install where clawhub was never added, a registry entry disabled during a security review, a typo/casing mismatch in the name, or picoclaw loading a different config.json than the one edited.

Related errors


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