kubernetes/kops · error

failed to parse kubernetes version (%s): %w

Error message

failed to parse kubernetes version (%s): %w

What it means

ParseKubernetesVersion wraps any failure converting the numeric minor captured from a version-URL-like string (e.g. .../v1.23/) into a semver.Version. It fires when semver.ParseTolerant fails but the string matches versionURLPattern, and the extracted minor component is not a valid integer. The error preserves the original input and the underlying strconv error via %w.

Source

Thrown at pkg/apis/kops/util/versions.go:36

import (
	"fmt"
	"regexp"
	"strconv"

	"github.com/blang/semver/v4"
	"k8s.io/klog/v2"
)

var versionURLPattern = regexp.MustCompile(`/v1\.([\d]+)\.`)

func ParseKubernetesVersion(version string) (*semver.Version, error) {
	sv, err := semver.ParseTolerant(version)
	if err != nil {
		if submatch := versionURLPattern.FindStringSubmatch(version); len(submatch) >= 2 {
			minor, err := strconv.Atoi(submatch[1])
			if err != nil {
				return nil, fmt.Errorf("failed to parse kubernetes version (%s): %w", version, err)
			}
			sv = semver.Version{Major: 1, Minor: uint64(minor)}
		} else {
			klog.Errorf("unable to parse Kubernetes version %q", version)
			return nil, fmt.Errorf("unable to parse kubernetes version %q", version)
		}
		klog.V(1).Infof("Kubernetes version %q string matched to %v", version, sv)
	}

	return &sv, nil
}

// Deprecated: prefer using KubernetesVersion.IsGTE()
func IsKubernetesGTE(version string, k8sVersion semver.Version) bool {
	parsedVersion, err := ParseKubernetesVersion(version)
	if err != nil {
		panic(fmt.Sprintf("Error parsing version %s: %v", version, err))
	}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Set the kubernetesVersion in the cluster spec to a plain semantic version like 1.28.4
  2. Verify the string actually matches the expected version-URL format (numeric minor) before parsing
  3. Use ParseKubernetesVersionInline/NormaliseKubernetesVersion or strip URL prefixes manually first
  4. Log and inspect the offending version value; fix the upstream config source producing it

Example fix

// before
v, err := ParseKubernetesVersion("https://storage.googleapis.com/k8s/release/vX.23")
// after
v, err := ParseKubernetesVersion("1.23.0")
Defensive patterns

Strategy: validation

Validate before calling

re, _ := regexp.Compile(`/v1\.[0-9]+/?$`)
sv, err := semver.ParseTolerant(version)
if err != nil && !re.MatchString(version) {
    return fmt.Errorf("invalid kubernetes version %q", version)
}
_, err = util.ParseKubernetesVersion(version)
if err != nil { /* abort before calling kops APIs */ }

Type guard

func isParseableKubernetesVersion(v string) bool {
    _, err := util.ParseKubernetesVersion(v)
    return err == nil
}

Try / catch

sv, err := util.ParseKubernetesVersion(raw)
if err != nil {
    klog.Warningf("skipping unparseable kubernetes version %q: %v", raw, err)
    return nil
}

Prevention

When it happens

Trigger: Calling ParseKubernetesVersion (directly or via IsKubernetesGTE, IsGTE, RecommendedKubernetesVersion, FindRecommendedUpgrade, IsUpgradeRequired) with a string that fails strict/tolerant semver parsing but matches the version URL regex, where the regex's minor group is non-numeric (e.g. 'vX.abc' style URL).

Common situations: KubernetesVersion configured to a URL or image tag fragment instead of a plain version; cluster spec values copied from container image names; automated tooling substituting placeholders into the version field.

Understand the failure class

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/f4a9d2635a1cc53f. Report an issue: GitHub.