router-for-me/CLIProxyAPI · error
invalid plugin version %q
Error message
invalid plugin version %q
What it means
Manifest.Validate() rejects the plugin manifest's version field. The version is trimmed and normalizeVersion() strips at most one leading 'v'/'V', then validPluginVersion() requires a non-empty string that does not still start with 'v' and matches ^[0-9][0-9A-Za-z.+-]*$. Anything else (letters first, spaces, 'vv' prefix, empty after trim is caught earlier) fails with this error.
Source
Thrown at internal/pluginstore/manifest.go:108
Install: NormalizeInstallPlan(m.Install),
}
}
func (m Manifest) InstallType() string {
installType := strings.ToLower(strings.TrimSpace(m.Install.Type))
if installType == "" {
return InstallTypeGitHubRelease
}
return installType
}
func (m Manifest) Validate() error {
version := strings.TrimSpace(m.Version)
if version == "" {
return fmt.Errorf("missing required field version")
}
if !validPluginVersion(normalizeVersion(version)) {
return fmt.Errorf("invalid plugin version %q", m.Version)
}
switch m.InstallType() {
case InstallTypeDirect:
if m.SchemaVersion != 0 && m.SchemaVersion != SchemaVersionV2 {
return fmt.Errorf("unsupported schema-version %d", m.SchemaVersion)
}
if errID := validateManifestPluginID(m.ID); errID != nil {
return errID
}
plan := NormalizeInstallPlan(m.Install)
plan.Type = InstallTypeDirect
if len(plan.Artifacts) > 0 {
if errValidate := ValidateInstallPlan(plan); errValidate != nil {
return errValidate
}
return validatePinnedArtifactURLs(plan.Artifacts)
}
return validateManifestSourceURL(m.SourceURL)View on GitHub (pinned to 78f0c4079e)
Solutions
- Set version to a plain dotted number, e.g. "1.2.3" (a single leading "v1.2.3" is also accepted because normalizeVersion strips it)
- Remove spaces, unicode, and any second leading 'v' from the version string
- If you need a tag-like name, remember only the version field is strict — put tags in release-tag for github-release installs and keep version numeric
Example fix
// before
manifest := pluginstore.Manifest{Version: "release-1.0"}
err := manifest.Validate() // invalid plugin version "release-1.0"
// after
manifest := pluginstore.Manifest{Version: "1.0.0"}
err := manifest.Validate() // nil Defensive patterns
Strategy: validation
Validate before calling
var versionRe = regexp.MustCompile(`^[0-9][0-9A-Za-z.+-]*$`)
func versionOK(v string) bool {
v = strings.TrimSpace(v)
if len(v) > 1 && (v[0] == 'v' || v[0] == 'V') { v = v[1:] }
return v != "" && !strings.HasPrefix(v, "v") && versionRe.MatchString(v)
}
// before submit:
if !versionOK(m.Version) { return fmt.Errorf("fix version %q", m.Version) } Type guard
func validManifestVersion(v string) bool { return versionOK(v) } Try / catch
err := m.Validate()
if err != nil {
if strings.Contains(err.Error(), "invalid plugin version") { /* fix version field, re-validate */ }
return err
} Prevention
- Render version from a single semver variable in release automation
- Lint manifests in CI with a regex gate before publish
- Never copy branch or tag names with letters-first prefixes into version
When it happens
Trigger: Calling pluginstore Manifest.Validate() (directly or via registry install/publish flows) with m.Version set to e.g. "alpha-1", "v_v1", " 1.0 β", "vv1.2.3", or any value whose first character after trimming one optional 'v' is not a digit.
Common situations: Hand-edited plugin manifest YAML/JSON using tags like "release-1.0" or "latest"; copying a Git branch name into version; double 'v' from templating ("v" + "v1.0.0"); non-ASCII or whitespace sneaking in from copy-paste.
Related errors
- unsupported install type %q
- missing required field version
- unsupported schema-version %d
- missing required field release-tag
- missing required field id
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/1342157950492024.
Report an issue: GitHub.