coreybutler/nvm-windows · error

Invalid character(s) found in patch number %q

Error message

Invalid character(s) found in patch number %q

What it means

Semver parse error from the vendored github.com/coreos/go-semver NewVersion(): the patch segment (third dotted component of the version string, before any prerelease/build suffix) contains characters outside [0-9]. It is returned when containsOnly(patch, numbers) fails.

Source

Thrown at src/semver/semver.go:236

	var subVersionIndex int
	if preIndex != -1 && buildIndex == -1 {
		subVersionIndex = preIndex
	} else if preIndex == -1 && buildIndex != -1 {
		subVersionIndex = buildIndex
	} else if preIndex == -1 && buildIndex == -1 {
		subVersionIndex = len(parts[2])
	} else {
		// if there is no actual pr version but a hyphen inside the build meta data
		if buildIndex < preIndex {
			subVersionIndex = buildIndex
			preIndex = -1 // Build meta data before preIndex found implicates there are no prerelease versions
		} else {
			subVersionIndex = preIndex
		}
	}

	if !containsOnly(parts[2][:subVersionIndex], numbers) {
		return nil, fmt.Errorf("Invalid character(s) found in patch number %q", parts[2][:subVersionIndex])
	}
	if hasLeadingZeroes(parts[2][:subVersionIndex]) {
		return nil, fmt.Errorf("Patch number must not contain leading zeroes %q", parts[2][:subVersionIndex])
	}
	patch, err := strconv.ParseUint(parts[2][:subVersionIndex], 10, 64)
	if err != nil {
		return nil, err
	}
	v := &Version{}
	v.Major = major
	v.Minor = minor
	v.Patch = patch

	// There are PreRelease versions
	if preIndex != -1 {
		var preRels string
		if buildIndex != -1 {
			preRels = parts[2][subVersionIndex+1 : buildIndex]

View on GitHub (pinned to 5b18223ca1)

Solutions

  1. Normalize input to strict semver (MAJOR.MINOR.PATCH with optional -prerelease +build) before parsing
  2. Strip prefixes like 'v' and any stray whitespace/labels before calling NewVersion
  3. If loose parsing is needed, pre-validate with a regex and extract the numeric core first

Example fix

// before
v, err := semver.NewVersion("1.2.x")

// after
v, err := semver.NewVersion("1.2.0")
// or normalize:
s := strings.TrimPrefix(strings.TrimSpace(raw), "v")
v, err := semver.NewVersion(s)
Defensive patterns

Strategy: type-guard

Validate before calling

var semverCore = regexp.MustCompile(`^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z.]+)?(?:\+[0-9A-Za-z.]+)?$`)
func isParsable(v string) bool { return semverCore.MatchString(strings.TrimSpace(v)) }

Type guard

func isStrictSemver(v string) bool {
    return regexp.MustCompile(`^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(-[0-9A-Za-z]+(\.[0-9A-Za-z]+)*)?(\+[0-9A-Za-z]+(\.[0-9A-Za-z]+)*)?$`).MatchString(strings.TrimSpace(v))
}

Try / catch

if _, err := semver.NewVersion(input); err != nil {
    if strings.Contains(err.Error(), "Invalid character(s) found in patch") {
        input = sanitizeVersion(input) // strip junk, retry with cleaned string
    }
}

Prevention

When it happens

Trigger: Calling semver.NewVersion (directly or via nvm version parsing) with inputs like "1.2.x", "1.2.3a", "1.2.-3", or "1.2.3 beta" where the patch slice up to the first '-'/'+' holds non-numeric characters.

Common situations: Passing version strings from npm registries or user input with unexpected formats (e.g. partial versions, 'latest', suffixed strings); parsing dist-tags or loose versions like "v1.2" style not accepted by this strict parser.

Understand the failure class

Related errors


AI-assisted analysis of coreybutler/nvm-windows@5b18223ca1 (2026-08-15). Data as JSON: /api/errors/f5e71fbe487c1d27. Report an issue: GitHub.