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
- Deduplicate items by manifest ID in the sync index before serving
- If two distinct plugins are meant, give one a different ID
- 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
- Deduplicate by trimmed ID when building or merging sync indexes
- Index CI: assert uniqueness of IDs across the payload
- When consuming, keep only the first occurrence rather than failing hard if partial data is acceptable
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
- plugin sync item %d: %w
- direct plugin sync manifest requires pinned artifacts
- unsupported plugin sync schema_version %d
- plugin sync response missing expires_at
- plugin sync item %d auth %d: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/6351d486be54a7fe.
Report an issue: GitHub.