kubernetes/kops · error

unable to parse kubernetes version %q

Error message

unable to parse kubernetes version %q

What it means

ParseKubernetesVersion returns this when the input is neither a valid (tolerant) semver string nor a version-URL-like string. It logs the unparseable value and returns a descriptive error quoting the original input. This is the terminal fallback for any unrecognized Kubernetes version format.

Source

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

	"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))
	}

	// Ignore Pre & Build fields
	k8sVersion.Pre = nil
	k8sVersion.Build = nil

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Correct the kubernetesVersion value to a valid semver string (e.g. 1.28.4 or 1.28)
  2. Check for empty/missing configuration values feeding the version field
  3. If using a URL form, ensure it matches the kops version URL pattern with a numeric minor
  4. Run kops get cluster --name X -o yaml to inspect the stored kubernetesVersion and fix it via kops replace

Example fix

// before
KubernetesVersion: "latest"
// after
KubernetesVersion: "1.28.4"
Defensive patterns

Strategy: validation

Validate before calling

if strings.TrimSpace(v) == "" {
    return errors.New("kubernetesVersion is empty")
}
if _, err := semver.ParseTolerant(v); err != nil {
    return fmt.Errorf("kubernetesVersion %q is not a valid version", v)
}

Type guard

func isWellFormedVersion(v string) bool {
    _, err := semver.ParseTolerant(strings.TrimSpace(v))
    return err == nil
}

Try / catch

_, err := util.ParseKubernetesVersion(v)
if err != nil {
    if strings.Contains(err.Error(), "unable to parse") {
        return fmt.Errorf("fix kubernetesVersion %q: must look like 1.28.4", v)
    }
    return err
}

Prevention

When it happens

Trigger: Passing any string to ParseKubernetesVersion (or callers IsKubernetesGTE, IsGTE, RecommendedKubernetesVersion, FindRecommendedUpgrade, IsUpgradeRequired) that does not parse as semver and does not match versionURLPattern — e.g. empty string, 'latest', '1.2x', or a URL without a minor digit.

Common situations: Empty or unset kubernetesVersion field; typos like '1..28'; using channel labels ('stable', 'latest') instead of versions; copying image repository names into the version field; upstream change to kops version-channel data.

Understand the failure class

Related errors


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