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

  1. 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)
  2. Remove spaces, unicode, and any second leading 'v' from the version string
  3. 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

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


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