{"record":{"id":"f0d91e2c5821047a","repo":"router-for-me/CLIProxyAPI","slug":"plugin-sync-item-d-w","errorCode":null,"errorMessage":"plugin sync item %d: %w","messagePattern":"plugin sync item (.+?): %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/pluginstore/home_sync.go","lineNumber":64,"sourceCode":"\nfunc (r *PluginSyncResponse) Validate(now time.Time) error {\n\tif r == nil {\n\t\treturn fmt.Errorf(\"plugin sync response is nil\")\n\t}\n\tif r.SchemaVersion != PluginSyncSchemaVersion {\n\t\treturn fmt.Errorf(\"unsupported plugin sync schema_version %d\", r.SchemaVersion)\n\t}\n\tif r.ExpiresAt.IsZero() {\n\t\treturn fmt.Errorf(\"plugin sync response missing expires_at\")\n\t}\n\tif !now.Before(r.ExpiresAt) {\n\t\treturn fmt.Errorf(\"plugin sync response expired\")\n\t}\n\tseen := make(map[string]struct{}, len(r.Items))\n\tfor index := range r.Items {\n\t\titem := &r.Items[index]\n\t\tif errManifest := item.Manifest.Validate(); errManifest != nil {\n\t\t\treturn fmt.Errorf(\"plugin sync item %d: %w\", index, errManifest)\n\t\t}\n\t\tif errURLs := validatePluginSyncManifestURLs(item.Manifest); errURLs != nil {\n\t\t\treturn fmt.Errorf(\"plugin sync item %d: %w\", index, errURLs)\n\t\t}\n\t\tid := strings.TrimSpace(item.Manifest.ID)\n\t\tif _, exists := seen[id]; exists {\n\t\t\treturn fmt.Errorf(\"plugin sync response contains duplicate plugin %q\", id)\n\t\t}\n\t\tseen[id] = struct{}{}\n\t\tfor authIndex := range item.Auth {\n\t\t\tif errAuth := ValidateResolvedAuthConfig(item.Auth[authIndex]); errAuth != nil {\n\t\t\t\treturn fmt.Errorf(\"plugin sync item %d auth %d: %w\", index, authIndex, errAuth)\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/pluginstore/home_sync.go#L46-L82","documentation":"While validating each item in the sync response, item.Manifest.Validate() failed and the error is wrapped with the item's index ('plugin sync item N: ...'). The underlying message names the actual manifest defect (bad/missing ID, name, version, and so on). This variant specifically points at manifest-structure problems as opposed to URL policy (error 629).","triggerScenarios":"Validate on a sync response where item N's manifest fails its own Validate — missing required fields, malformed ID/version strings, invalid install block.","commonSituations":"Plugin index entry edited by hand with a missing id or version; a plugin author pushing a manifest the client's stricter validation rejects after an upgrade.","solutions":["Read the wrapped error text — it names the exact manifest field problem","Fix the manifest at index N in the sync index (server side) or remove the entry","Upgrade the client if the manifest uses a newer legitimate format","Re-fetch the index; transient serving of a broken file resolves on refresh"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"for i := range resp.Items {\n    if err := resp.Items[i].Manifest.Validate(); err != nil {\n        return fmt.Errorf(\"pre-check item %d manifest: %w\", i, err)\n    }\n}","typeGuard":null,"tryCatchPattern":"var idxErr error\nif err != nil && strings.Contains(err.Error(), \"plugin sync item\") {\n    // parse index from message; fix/drop that entry server-side, or skip that plugin locally\n}","preventionTips":["Validate manifests before publishing them to the index","Run client-side pre-validation of items you plan to install","Surface the wrapped cause — it names the exact broken field"],"tags":["manifest","validation","sync","go"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}