kubernetes/kops · error

unable to determine kubernetes version from %q

Error message

unable to determine kubernetes version from %q

What it means

NewOptionsContext parses cluster.spec.kubernetesVersion with util.ParseKubernetesVersion to populate the options context. An empty or unparseable version string (not semver-ish, junk text) makes it impossible to compute component defaults, so construction fails with this error.

Source

Thrown at pkg/model/components/context.go:58

	// Deprecated: Prefer using NodeKubernetesVersion() and ControlPlaneKubernetesVersion()
	KubernetesVersion semver.Version

	AssetBuilder *assets.AssetBuilder

	nodeKubernetesVersion         kopsmodel.KubernetesVersion
	controlPlaneKubernetesVersion kopsmodel.KubernetesVersion
}

func NewOptionsContext(cluster *kops.Cluster, assetBuilder *assets.AssetBuilder, maxKubeletSupportedVersion string) (*OptionsContext, error) {
	optionsContext := &OptionsContext{
		ClusterName:  cluster.ObjectMeta.Name,
		AssetBuilder: assetBuilder,
	}

	sv, err := util.ParseKubernetesVersion(cluster.Spec.KubernetesVersion)
	if err != nil {
		return nil, fmt.Errorf("unable to determine kubernetes version from %q", cluster.Spec.KubernetesVersion)
	}
	optionsContext.KubernetesVersion = *sv

	controlPlaneKubernetesVersion, err := kopsmodel.ParseKubernetesVersion(cluster.Spec.KubernetesVersion)
	if err != nil {
		return nil, fmt.Errorf("unable to determine kubernetes version from %q: %w", cluster.Spec.KubernetesVersion, err)
	}
	nodeKubernetesVersion := controlPlaneKubernetesVersion
	if maxKubeletSupportedVersion != "" {
		nodeKubernetesVersion, err = kopsmodel.ParseKubernetesVersion(maxKubeletSupportedVersion)
		if err != nil {
			return nil, fmt.Errorf("unable to determine kubernetes version from %q: %w", maxKubeletSupportedVersion, err)
		}
	}

	optionsContext.nodeKubernetesVersion = *nodeKubernetesVersion
	optionsContext.controlPlaneKubernetesVersion = *controlPlaneKubernetesVersion

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Set an explicit valid version, e.g. `kops create cluster --kubernetes-version v1.30.4 ...`
  2. If you intended the default, omit the field entirely so kops picks its default version
  3. Check the CI variable substitution — ensure KUBERNETES_VERSION is not empty

Example fix

# before (empty via unset var)
kops create cluster ... --kubernetes-version "$VER"
# after
export VER=v1.30.4
kops create cluster ... --kubernetes-version "$VER"
Defensive patterns

Strategy: validation

Validate before calling

if _, err := util.ParseKubernetesVersion(cluster.Spec.KubernetesVersion); err != nil {
	return fmt.Errorf("--kubernetes-version must be valid semver, got %q", cluster.Spec.KubernetesVersion)
}

Type guard

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

Try / catch

if err := createCluster(); err != nil {
	if strings.Contains(err.Error(), "unable to determine kubernetes version") {
		// fall back to `kops get instancegroup`-style default version
	}
	return err
}

Prevention

When it happens

Trigger: cluster.Spec.KubernetesVersion is empty, or set to a non-parseable value (e.g. 'latest', 'v1', 'stable', or a plain git hash without semver metadata).

Common situations: Creating a cluster without --kubernetes-version; CI scripts substituting an unset variable (empty string); hand-edited manifests with arbitrary version strings.

Related errors


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