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
- Align the version argument with what the tag actually resolves to (check the release's reported version)
- Use the exact, immutable version tag for the release instead of floating tags like 'latest'
- 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
- Pin installs to immutable version tags, not floating ones
- Verify tag->version agreement before large-scale installs
- Treat this error as tamper detection — do not blindly update the pin
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
- invalid plugin version %q
- download %s: %w
- download checksums.txt: %w
- invalid plugin id %q
- download artifact: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/499346b568cef2db.
Report an issue: GitHub.