router-for-me/CLIProxyAPI · error
release tag is required
Error message
release tag is required
What it means
FetchReleaseByTag resolves a specific published release via /releases/tags/{tag}. After trimming, an empty tag string is rejected with 'release tag is required' before any network call is made. This is pure input validation on the tag parameter, independent of the plugin repository.
Source
Thrown at internal/pluginstore/github.go:91
if errDownload != nil {
return Release{}, errDownload
}
var release Release
if errDecode := json.Unmarshal(data, &release); errDecode != nil {
return Release{}, fmt.Errorf("decode release: %w", errDecode)
}
return release, nil
}
// FetchReleaseByTag returns a published release by its exact GitHub tag.
func (c Client) FetchReleaseByTag(ctx context.Context, plugin Plugin, tag string) (Release, error) {
owner, repo, errRepository := GitHubRepositoryParts(plugin.Repository)
if errRepository != nil {
return Release{}, errRepository
}
tag = strings.TrimSpace(tag)
if tag == "" {
return Release{}, fmt.Errorf("release tag is required")
}
releaseURL := fmt.Sprintf(
"https://api.github.com/repos/%s/%s/releases/tags/%s",
url.PathEscape(owner),
url.PathEscape(repo),
url.PathEscape(tag),
)
data, errDownload := c.get(ctx, releaseURL, "application/vnd.github+json", RequestKindMetadata, 0)
if errDownload != nil {
return Release{}, errDownload
}
var release Release
if errDecode := json.Unmarshal(data, &release); errDecode != nil {
return Release{}, fmt.Errorf("decode release: %w", errDecode)
}
return release, nil
}
View on GitHub (pinned to 78f0c4079e)
Solutions
- Check the source of the tag — usually the plugin manifest's version or pin field is empty; populate it.
- Default to the latest release path (FetchLatestRelease) when no explicit tag is configured.
- Validate the tag is non-empty right after parsing your config and fail with a clearer configuration error.
Example fix
// before
release, err := client.FetchReleaseByTag(ctx, plugin, plugin.Version) // "" -> 'release tag is required'
// after
tag := strings.TrimSpace(plugin.Version)
if tag == "" {
return client.FetchLatestRelease(ctx, plugin)
}
release, err := client.FetchReleaseByTag(ctx, plugin, tag) Defensive patterns
Strategy: validation
Validate before calling
tag := strings.TrimSpace(cfgPin)
if tag == "" {
return fmt.Errorf("plugin %s: version pin missing in config", plugin.Name)
} Type guard
func hasReleaseTag(tag string) bool { return strings.TrimSpace(tag) != "" } Prevention
- Require a version pin in config for by-tag installs or fall back to FetchLatestRelease.
- Fail config validation early instead of at fetch time.
When it happens
Trigger: Calling FetchReleaseByTag(ctx, plugin, tag) where tag is "", whitespace-only, or a value that normalizes to empty (e.g. a missing manifest field passed through).
Common situations: Plugin manifest has an empty version/tag field; caller derives the tag from user input or a template and forgets a default; trailing/leading spaces are trimmed so only genuinely empty inputs trigger it.
Related errors
- invalid release tag %q
- asset %q missing download url
- count must be a positive integer
- Codex live multipart boundary is missing
- Codex live multipart body requires an sdp field
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/4cef098a8a402286.
Report an issue: GitHub.