router-for-me/CLIProxyAPI · error

release tag %q resolved version %q, want %q

Error message

release tag %q resolved version %q, want %q

What it means

InstallVersion fetched the release by tag and derived its version via ReleaseVersion, but that version differs from the version argument — the check is an exact string comparison. This pins installs to immutable version content: a tag that was moved or a tag/version mismatch (like a 'latest' tag) is rejected rather than silently installing different bits.

Source

Thrown at internal/pluginstore/install.go:110

	options = normalizeInstallOptions(options)
	version = normalizeVersion(version)
	if !validPluginVersion(version) {
		return InstallResult{}, fmt.Errorf("invalid plugin version %q", version)
	}
	releaseTag = strings.TrimSpace(releaseTag)
	if releaseTag == "" {
		releaseTag = version
	}
	release, errRelease := c.FetchReleaseByTag(ctx, plugin, releaseTag)
	if errRelease != nil {
		return InstallResult{}, errRelease
	}
	releaseVersion, errVersion := ReleaseVersion(release)
	if errVersion != nil {
		return InstallResult{}, errVersion
	}
	if releaseVersion != version {
		return InstallResult{}, fmt.Errorf("release tag %q resolved version %q, want %q", releaseTag, releaseVersion, version)
	}
	plugin.Version = version
	return c.installRelease(ctx, plugin, release, version, options)
}

func (c Client) installRelease(ctx context.Context, plugin Plugin, release Release, version string, options InstallOptions) (InstallResult, error) {
	archiveAsset, checksumAsset, errAssets := SelectReleaseAssets(release, plugin.ID, plugin.Version, options.GOOS, options.GOARCH)
	if errAssets != nil {
		return InstallResult{}, errAssets
	}
	archiveData, errArchive := c.DownloadAsset(ctx, archiveAsset)
	if errArchive != nil {
		return InstallResult{}, fmt.Errorf("download %s: %w", archiveAsset.Name, errArchive)
	}
	checksumData, errChecksum := c.DownloadAsset(ctx, checksumAsset)
	if errChecksum != nil {
		return InstallResult{}, fmt.Errorf("download checksums.txt: %w", errChecksum)
	}

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Align the version argument with what the tag actually resolves to (check the release's reported version)
  2. Use the exact, immutable version tag for the release instead of floating tags like 'latest'
  3. If the tag was legitimately re-published, update the pinned version in your config/lockfile

Example fix

// before
client.InstallVersion(ctx, plugin, "latest", "1.0.0", opts)

// after
client.InstallVersion(ctx, plugin, "v1.0.0", "1.0.0", opts)
Defensive patterns

Strategy: validation

Validate before calling

release, err := client.FetchReleaseByTag(ctx, plugin, tag)
if err != nil { return err }
resolved, err := pluginstore.ReleaseVersion(release)
if err != nil { return err }
if resolved != version {
    return fmt.Errorf("tag %q moved to %s; update pin or use exact tag", tag, resolved)
}

Try / catch

if err != nil && strings.Contains(err.Error(), "resolved version") {
    // re-pin config to the resolved version, or pin the exact version tag
}

Prevention

When it happens

Trigger: InstallVersion(plugin, "v2", "1.0.0") where tag v2's release reports version 2.0.0; using a floating tag (latest/edge) whose release version differs from the version you declared; release tag renamed/re-published after you captured the version.

Common situations: Hardcoded version in a lockfile while the tag was re-pointed; passing a tag-derived version with different formatting (though normalizeVersion strips 'v', other differences still fail); mutable tags in CI.

Related errors


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