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

  1. Check the source of the tag — usually the plugin manifest's version or pin field is empty; populate it.
  2. Default to the latest release path (FetchLatestRelease) when no explicit tag is configured.
  3. 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

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


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