{"record":{"id":"739f6fd3b71052ba","repo":"router-for-me/CLIProxyAPI","slug":"plugin-install-failed","errorCode":"plugin_install_failed","errorMessage":"%s: %w","messagePattern":"%s: %w","errorType":"http","errorClass":null,"httpStatus":502,"severity":"error","filePath":"internal/api/handlers/management/plugin_store.go","lineNumber":400,"sourceCode":"\t\t}\n\t\treturn pluginstore.ManifestFromPlugin(source, plugin)\n\t}\n\treturn pluginstore.Manifest{}, fmt.Errorf(\"direct plugin version %q not found\", version)\n}\n\nfunc installPluginStoreGitHubRelease(ctx context.Context, client pluginstore.Client, plugin pluginstore.Plugin, requestedVersion string, options pluginstore.InstallOptions) (pluginstore.InstallResult, error) {\n\tversion := normalizePluginStoreRequestedVersion(requestedVersion)\n\tif version == \"\" {\n\t\treturn client.Install(ctx, plugin, options)\n\t}\n\ttags := pluginStoreReleaseTagCandidates(requestedVersion)\n\terrs := make([]error, 0, len(tags))\n\tfor _, tag := range tags {\n\t\tresult, errInstall := client.InstallVersion(ctx, plugin, tag, version, options)\n\t\tif errInstall == nil {\n\t\t\treturn result, nil\n\t\t}\n\t\terrs = append(errs, fmt.Errorf(\"%s: %w\", tag, errInstall))\n\t}\n\treturn pluginstore.InstallResult{}, fmt.Errorf(\"install release by tag: %w\", errors.Join(errs...))\n}\n\nfunc pluginStoreManifestForInstall(source pluginstore.Source, plugin pluginstore.Plugin, result pluginstore.InstallResult) (pluginstore.Manifest, error) {\n\tinstallType := strings.TrimSpace(result.InstallType)\n\tif installType == \"\" {\n\t\tinstallType = pluginstore.PluginInstallType(plugin)\n\t}\n\tswitch installType {\n\tcase pluginstore.InstallTypeDirect:\n\t\tplugin.Version = strings.TrimSpace(result.Version)\n\t\tplugin.Install = pluginstore.NormalizeInstallPlan(plugin.Install)\n\t\treturn pluginstore.ManifestFromPlugin(source, plugin)\n\tcase pluginstore.InstallTypeGitHubRelease:\n\t\treleaseTag := strings.TrimSpace(result.ReleaseTag)\n\t\tif releaseTag == \"\" {\n\t\t\treturn pluginstore.Manifest{}, fmt.Errorf(\"release tag is required\")","sourceCodeStart":382,"sourceCodeEnd":418,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/api/handlers/management/plugin_store.go#L382-L418","documentation":"Wrapped error produced inside installPluginStoreGitHubRelease (plugin_store.go:400) with code plugin_install_failed: each failed attempt to install a GitHub-release plugin from one tag candidate is wrapped as \"<tag>: <cause>\" and collected. These per-tag errors are then joined into the final 'install release by tag' error, so this message appears as a component line inside errors.Join output.","triggerScenarios":"One of the two tag candidates (the raw version and its 'v'-prefixed twin from pluginStoreReleaseTagCandidates) failing in client.InstallVersion: release tag not found, asset download blocked, extraction failure, checksum mismatch. You normally see this string as part of the joined error, not alone.","commonSituations":"GitHub API rate limiting or network egress restrictions from the server; releases tagged without the 'v' convention so one candidate always 404s; private repos without a token.","solutions":["Read the joined error: it contains one 'tag: cause' line per candidate; address the underlying cause (404, rate limit, TLS, auth)","Confirm the release actually exists and note its exact tag: curl https://api.github.com/repos/<owner>/<repo>/releases","For rate limits, wait or configure GitHub credentials used by the store client","If the release uses a nonstandard tag scheme, request the full tag exactly as published"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Pre-flight: confirm at least one tag candidate exists before installing.\ntags := []string{version, \"v\" + version}\nfor _, tag := range tags {\n\tresp, err := http.Head(fmt.Sprintf(\"https://github.com/%s/releases/tag/%s\", repo, tag))\n\tif err == nil && resp.StatusCode == http.StatusOK {\n\t\treturn // a candidate exists\n\t}\n}\nreturn fmt.Errorf(\"no release tag found for %s\", version)","typeGuard":null,"tryCatchPattern":"var err error\nfor attempt := 0; attempt < 3; attempt++ {\n\t_, err = installPluginStoreGitHubRelease(ctx, client, plugin, version, opts)\n\tif err == nil {\n\t\tbreak\n\t}\n\tif isTransient(err) { // rate limit, network: inspect joined causes\n\t\ttime.Sleep(time.Duration(attempt+1) * 2 * time.Second)\n\t\tcontinue\n\t}\n\tbreak\n}","preventionTips":["Read the per-tag causes in the joined error instead of retrying blindly","Verify releases exist (and have assets) before scripting pinned installs","Configure GitHub credentials and ensure egress to github.com for the server host"],"tags":["plugins","plugin-store","github-release","install","error-wrapping"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}