router-for-me/CLIProxyAPI · error

plugin_install_failed

plugin_install_failed

Error message

%s: %w

What it means

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.

Source

Thrown at internal/api/handlers/management/plugin_store.go:400

		}
		return pluginstore.ManifestFromPlugin(source, plugin)
	}
	return pluginstore.Manifest{}, fmt.Errorf("direct plugin version %q not found", version)
}

func installPluginStoreGitHubRelease(ctx context.Context, client pluginstore.Client, plugin pluginstore.Plugin, requestedVersion string, options pluginstore.InstallOptions) (pluginstore.InstallResult, error) {
	version := normalizePluginStoreRequestedVersion(requestedVersion)
	if version == "" {
		return client.Install(ctx, plugin, options)
	}
	tags := pluginStoreReleaseTagCandidates(requestedVersion)
	errs := make([]error, 0, len(tags))
	for _, tag := range tags {
		result, errInstall := client.InstallVersion(ctx, plugin, tag, version, options)
		if errInstall == nil {
			return result, nil
		}
		errs = append(errs, fmt.Errorf("%s: %w", tag, errInstall))
	}
	return pluginstore.InstallResult{}, fmt.Errorf("install release by tag: %w", errors.Join(errs...))
}

func pluginStoreManifestForInstall(source pluginstore.Source, plugin pluginstore.Plugin, result pluginstore.InstallResult) (pluginstore.Manifest, error) {
	installType := strings.TrimSpace(result.InstallType)
	if installType == "" {
		installType = pluginstore.PluginInstallType(plugin)
	}
	switch installType {
	case pluginstore.InstallTypeDirect:
		plugin.Version = strings.TrimSpace(result.Version)
		plugin.Install = pluginstore.NormalizeInstallPlan(plugin.Install)
		return pluginstore.ManifestFromPlugin(source, plugin)
	case pluginstore.InstallTypeGitHubRelease:
		releaseTag := strings.TrimSpace(result.ReleaseTag)
		if releaseTag == "" {
			return pluginstore.Manifest{}, fmt.Errorf("release tag is required")

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Read the joined error: it contains one 'tag: cause' line per candidate; address the underlying cause (404, rate limit, TLS, auth)
  2. Confirm the release actually exists and note its exact tag: curl https://api.github.com/repos/<owner>/<repo>/releases
  3. For rate limits, wait or configure GitHub credentials used by the store client
  4. If the release uses a nonstandard tag scheme, request the full tag exactly as published
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight: confirm at least one tag candidate exists before installing.
tags := []string{version, "v" + version}
for _, tag := range tags {
	resp, err := http.Head(fmt.Sprintf("https://github.com/%s/releases/tag/%s", repo, tag))
	if err == nil && resp.StatusCode == http.StatusOK {
		return // a candidate exists
	}
}
return fmt.Errorf("no release tag found for %s", version)

Try / catch

var err error
for attempt := 0; attempt < 3; attempt++ {
	_, err = installPluginStoreGitHubRelease(ctx, client, plugin, version, opts)
	if err == nil {
		break
	}
	if isTransient(err) { // rate limit, network: inspect joined causes
		time.Sleep(time.Duration(attempt+1) * 2 * time.Second)
		continue
	}
	break
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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