kubernetes/kops · error
cluster ownerRef not set on CAPI cluster %v/%v
Error message
cluster ownerRef not set on CAPI cluster %v/%v
What it means
getKopsClusterFromCAPICluster finds the kops Cluster that owns a CAPI Cluster by scanning capiCluster's ownerReferences for one with Kind "Cluster" and APIVersion prefixed "kops.k8s.io/". This error is thrown when no such owner reference exists, meaning the CAPI Cluster is not linked to any kops.k8s.io Cluster and the kops Cluster name cannot be derived.
Source
Thrown at pkg/controllers/clusterapi/utils.go:99
}
return capiCluster, nil
}
func getKopsClusterFromCAPICluster(ctx context.Context, kube client.Client, capiCluster *unstructured.Unstructured) (*kopsapi.Cluster, error) {
var clusterKey types.NamespacedName
for _, ownerRef := range capiCluster.GetOwnerReferences() {
if ownerRef.Kind == "Cluster" && strings.HasPrefix(ownerRef.APIVersion, "kops.k8s.io/") {
clusterKey = types.NamespacedName{
Namespace: capiCluster.GetNamespace(),
Name: ownerRef.Name,
}
}
}
if clusterKey.Name == "" {
return nil, fmt.Errorf("cluster ownerRef not set on CAPI cluster %v/%v", capiCluster.GetNamespace(), capiCluster.GetName())
}
cluster := &kopsapi.Cluster{}
if err := kube.Get(ctx, clusterKey, cluster); err != nil {
return nil, fmt.Errorf("error fetching cluster %v: %w", clusterKey, err)
}
return cluster, nil
}
func getKopsControlPlaneFromCAPICluster(ctx context.Context, kube client.Client, capiCluster *unstructured.Unstructured) (*v1beta1.KopsControlPlane, error) {
capiClusterKey := types.NamespacedName{
Namespace: capiCluster.GetNamespace(),
Name: capiCluster.GetName(),
}
name, _, _ := unstructured.NestedString(capiCluster.Object, "spec", "controlPlaneRef", "name")
if name == "" {
return nil, fmt.Errorf("controlPlaneRef.name not set for %v", capiClusterKey)View on GitHub (pinned to 4c8573c808)
Solutions
- Ensure the CAPI Cluster is created by the kops CAPI machinery so it sets the kops.k8s.io Cluster ownerRef; delete and recreate through the normal flow
- Manually add the correct ownerReference (apiVersion: kops.k8s.io/v1alpha2, kind: Cluster, name: <kops-cluster>) to the CAPI Cluster
- Verify the kops Cluster exists in the same namespace and its name matches the ownerRef
- Check for API version changes across kops upgrades that break the strings.HasPrefix(ownerRef.APIVersion, "kops.k8s.io/") match
Example fix
# before: CAPI Cluster without kops ownerRef
metadata:
name: my-capi-cluster
ownerReferences: []
# after
metadata:
name: my-capi-cluster
ownerReferences:
- apiVersion: kops.k8s.io/v1alpha2
kind: Cluster
name: my-kops-cluster
uid: <uid>
controller: true Defensive patterns
Strategy: validation
Validate before calling
func hasKopsOwnerRef(capiCluster *unstructured.Unstructured) bool {
for _, ref := range capiCluster.GetOwnerReferences() {
if ref.Kind == "Cluster" && strings.HasPrefix(ref.APIVersion, "kops.k8s.io/") {
return ref.Name != ""
}
}
return false
}
// skip reconciliation until hasKopsOwnerRef(capiCluster) is true Type guard
func kopsOwnerClusterKey(capiCluster *unstructured.Unstructured) (types.NamespacedName, bool) {
for _, ref := range capiCluster.GetOwnerReferences() {
if ref.Kind == "Cluster" && strings.HasPrefix(ref.APIVersion, "kops.k8s.io/") && ref.Name != "" {
return types.NamespacedName{Namespace: capiCluster.GetNamespace(), Name: ref.Name}, true
}
}
return types.NamespacedName{}, false
} Prevention
- Never create cluster.x-k8s.io Cluster objects manually; let the kops CAPI controller create them with the ownerRef
- Preserve ownerReferences when exporting/importing or editing Cluster manifests
- After kops upgrades, verify the ownerRef APIVersion still matches kops.k8s.io/*
- Use admission policies to reject CAPI Clusters lacking a kops.k8s.io ownerRef
When it happens
Trigger: Reconcile -> getKopsClusterFromCAPICluster where the CAPI Cluster object has an empty ownerReferences list, or owner references exist but none matches Kind=Cluster with APIVersion kops.k8s.io/* (e.g. owner is another kind, or a different API group).
Common situations: CAPI Cluster created manually instead of by the kops control-plane controller that normally sets the kops ownerRef; ownerRef stripped by copy/edit of the manifest; wrong owner kind or API version (e.g. kops.k8s.io vs another group) after a version migration.
Related errors
- error creating kops config template: %w
- error creating gcp machine template: %w
- error building machine deployments: %w
- clientset is not initialized
- node identity is required
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/485eb61fd338385b.
Report an issue: GitHub.