router-for-me/CLIProxyAPI · error

plugin sync response contains duplicate plugin %q

Error message

plugin sync response contains duplicate plugin %q

What it means

Two items in the sync response carry the same trimmed manifest ID. Validation tracks seen IDs in a map and rejects duplicates because plugin IDs must uniquely identify an install target — otherwise install/upgrade routing would be ambiguous.

Source

Thrown at internal/pluginstore/home_sync.go:71

	}
	if r.ExpiresAt.IsZero() {
		return fmt.Errorf("plugin sync response missing expires_at")
	}
	if !now.Before(r.ExpiresAt) {
		return fmt.Errorf("plugin sync response expired")
	}
	seen := make(map[string]struct{}, len(r.Items))
	for index := range r.Items {
		item := &r.Items[index]
		if errManifest := item.Manifest.Validate(); errManifest != nil {
			return fmt.Errorf("plugin sync item %d: %w", index, errManifest)
		}
		if errURLs := validatePluginSyncManifestURLs(item.Manifest); errURLs != nil {
			return fmt.Errorf("plugin sync item %d: %w", index, errURLs)
		}
		id := strings.TrimSpace(item.Manifest.ID)
		if _, exists := seen[id]; exists {
			return fmt.Errorf("plugin sync response contains duplicate plugin %q", id)
		}
		seen[id] = struct{}{}
		for authIndex := range item.Auth {
			if errAuth := ValidateResolvedAuthConfig(item.Auth[authIndex]); errAuth != nil {
				return fmt.Errorf("plugin sync item %d auth %d: %w", index, authIndex, errAuth)
			}
		}
	}
	return nil
}

func validatePluginSyncManifestURLs(manifest Manifest) error {
	if manifest.InstallType() != InstallTypeDirect {
		return nil
	}
	plan := NormalizeInstallPlan(manifest.Install)
	if len(plan.Artifacts) == 0 {
		return fmt.Errorf("direct plugin sync manifest requires pinned artifacts")

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Deduplicate items by manifest ID in the sync index before serving
  2. If two distinct plugins are meant, give one a different ID
  3. Re-fetch the index after the server-side fix; clear local cache
Defensive patterns

Strategy: validation

Validate before calling

ids := map[string]struct{}{}
for i := range resp.Items {
    id := strings.TrimSpace(resp.Items[i].Manifest.ID)
    if _, dup := ids[id]; dup {
        return fmt.Errorf("duplicate plugin %q at item %d", id, i)
    }
    ids[id] = struct{}{}
}

Try / catch

if err != nil && strings.Contains(err.Error(), "duplicate plugin") {
    // dedupe locally by ID (first wins) or reject the payload
}

Prevention

When it happens

Trigger: Validate on an index that lists the same plugin twice (identical or differently-cased/whitespace-padded IDs after TrimSpace; note the ID comparison itself is exact, so only exact matches after trim collide).

Common situations: Index merging two catalog sources that both include a popular plugin; a copy-paste entry; server-side dedup logic regressing.

Related errors


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