router-for-me/CLIProxyAPI · error

direct install plugin %q not found in source

Error message

direct install plugin %q not found in source

What it means

Returned during direct-install resolution when the registry was fetched successfully from the source URL but registry.PluginByID(manifest.ID) finds no entry with that ID. The manifest references a plugin the source registry does not know about. The library treats this as a hard mismatch because it cannot construct artifact coordinates for an unknown plugin.

Source

Thrown at internal/pluginstore/install.go:203

	if len(plugin.Install.Artifacts) > 0 {
		return plugin, nil
	}
	sourceURL := strings.TrimSpace(manifest.SourceURL)
	if sourceURL == "" {
		sourceURL = strings.TrimSpace(c.RegistryURL)
	}
	if sourceURL == "" {
		return Plugin{}, fmt.Errorf("direct install manifest missing source-url")
	}
	sourceClient := c
	sourceClient.RegistryURL = sourceURL
	registry, errRegistry := sourceClient.FetchRegistry(ctx)
	if errRegistry != nil {
		return Plugin{}, fmt.Errorf("fetch direct install source: %w", errRegistry)
	}
	resolved, okPlugin := registry.PluginByID(manifest.ID)
	if !okPlugin {
		return Plugin{}, fmt.Errorf("direct install plugin %q not found in source", strings.TrimSpace(manifest.ID))
	}
	if PluginInstallType(resolved) != InstallTypeDirect {
		return Plugin{}, fmt.Errorf("direct install plugin %q resolved as %q", strings.TrimSpace(manifest.ID), PluginInstallType(resolved))
	}
	return directPluginVersion(resolved, manifest.ID, manifest.Version)
}

func directPluginVersion(plugin Plugin, id string, version string) (Plugin, error) {
	id = strings.TrimSpace(id)
	version = normalizeVersion(version)
	if normalizeVersion(plugin.Version) == version {
		plugin.Version = version
		plugin.Install = NormalizeInstallPlan(plugin.Install)
		plugin.Install.Type = InstallTypeDirect
		if errPlan := ValidateInstallPlan(plugin.Install); errPlan != nil {
			return Plugin{}, fmt.Errorf("direct install plugin %q version %q: %w", id, version, errPlan)
		}
		return plugin, nil

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Fetch the registry document and confirm the exact plugin ID exists (compare case and spelling verbatim)
  2. Update manifest.ID to the current ID published by the source registry
  3. Point manifest.SourceURL at the registry that actually hosts the plugin

Example fix

// before
manifest.ID = "example-plugin " // trailing space or wrong name

// after
manifest.ID = "example-plugin" // exact ID as published in the source registry
plugin, err := client.ResolveDirect(ctx, manifest)
Defensive patterns

Strategy: validation

Validate before calling

func pluginExistsInRegistry(ctx context.Context, c pluginstore.Client, id string) (bool, error) {
    reg, err := c.FetchRegistry(ctx)
    if err != nil {
        return false, err
    }
    _, ok := reg.PluginByID(strings.TrimSpace(id))
    return ok, nil
}

Type guard

func isPluginNotFoundInSource(err error) bool {
    return err != nil && strings.Contains(err.Error(), "not found in source")
}

Try / catch

if err := client.ResolveDirect(ctx, manifest); err != nil {
    if isPluginNotFoundInSource(err) {
        // surface actionable message: list available IDs from FetchRegistry
    }
}

Prevention

When it happens

Trigger: manifest.ID is trimmed and looked up in the source registry; mismatch happens when the plugin was renamed, removed from the registry, the manifest was written against a different registry, or the ID has a typo/case difference.

Common situations: Plugin renamed upstream but local manifests still use the old ID; pointing SourceURL at the wrong registry (staging vs production); trailing whitespace or case differences in the ID; plugin deprecated and pruned from the registry; typo in a hand-edited manifest.

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/fc7b3ea03c8677e7. Report an issue: GitHub.