kubernetes/kops · error

label %q not set on %v

Error message

label %q not set on %v

What it means

getCAPIClusterFromCAPIObject resolves the parent cluster.x-k8s.io Cluster for any CAPI object by reading the well-known `cluster.x-k8s.io/cluster-name` label. This error is thrown when the object passed in (e.g. a Machine, MachineDeployment, or KopsControlPlane) has no value for that label, so the owning CAPI Cluster cannot be determined from the object alone.

Source

Thrown at pkg/controllers/clusterapi/utils.go:66

		{
			APIVersion: apiVersion,
			Kind:       kind,
			Name:       owner.GetName(),
			UID:        owner.GetUID(),
			Controller: new(true),
		},
	})
}

func getCAPIClusterFromCAPIObject(ctx context.Context, kube client.Client, obj client.Object) (*unstructured.Unstructured, error) {
	id := types.NamespacedName{
		Namespace: obj.GetNamespace(),
		Name:      obj.GetName(),
	}

	capiClusterName := obj.GetLabels()[clusterv1.ClusterNameLabel]
	if capiClusterName == "" {
		return nil, fmt.Errorf("label %q not set on %v", clusterv1.ClusterNameLabel, id)
	}

	capiCluster := &unstructured.Unstructured{}
	capiCluster.SetGroupVersionKind(schema.GroupVersionKind{
		Group:   "cluster.x-k8s.io",
		Version: "v1beta1",
		Kind:    "Cluster",
	})
	clusterKey := types.NamespacedName{
		Namespace: obj.GetNamespace(),
		Name:      capiClusterName,
	}
	if err := kube.Get(ctx, clusterKey, capiCluster); err != nil {
		return nil, fmt.Errorf("error fetching cluster %v: %w", clusterKey, err)
	}

	return capiCluster, nil
}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Add the label `cluster.x-k8s.io/cluster-name: <capi-cluster-name>` to the affected object
  2. Recreate the resource through the CAPI Cluster topology (e.g. via the ClusterClass or machine deployment) so CAPI sets the label itself
  3. Check cluster-api version — objects provisioned by very old CAPI releases may lack the label and need upgrading/patching
  4. Verify the reconciler is watching objects that belong to a CAPI-managed cluster at all

Example fix

// before (object missing label)
metadata:
  name: my-machine
  kind: Machine
// after
metadata:
  name: my-machine
  kind: Machine
  labels:
    cluster.x-k8s.io/cluster-name: my-cluster
Defensive patterns

Strategy: validation

Validate before calling

const ClusterNameLabel = "cluster.x-k8s.io/cluster-name"
func hasClusterNameLabel(obj client.Object) bool {
	return obj.GetLabels()[ClusterNameLabel] != ""
}
// before reconciling:
if !hasClusterNameLabel(obj) {
	// skip / requeue instead of calling getCAPIClusterFromCAPIObject
}

Type guard

func extractCAPIClusterName(obj client.Object) (string, bool) {
	name, ok := obj.GetLabels()["cluster.x-k8s.io/cluster-name"]
	if !ok || name == "" {
		return "", false
	}
	return name, true
}

Prevention

When it happens

Trigger: Reconcile calls getCAPIClusterFromCAPIObject with an object whose GetLabels()[clusterv1.ClusterNameLabel] returns "" — the `cluster.x-k8s.io/cluster-name` label is absent or empty on the reconciled resource.

Common situations: Resources created manually or by tooling that does not apply CAPI's standard topology labels; resources from an older CAPI version predating the label; hand-copied YAML missing metadata.labels; objects adopted from non-CAPI management.

Related errors


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