kubernetes/kops · error
CAPI Machine is missing cluster.x-k8s.io/deployment-name lab
Error message
CAPI Machine is missing cluster.x-k8s.io/deployment-name label
What it means
buildInstanceGroupFromCAPI derives an InstanceGroup from a CAPI Machine. kOps requires the machine to carry the cluster.x-k8s.io/deployment-name label to know which instance group it belongs to; this error is thrown when that label is empty.
Source
Thrown at cmd/kops-controller/pkg/server/node_config.go:125
}
if secret != nil && secret.Data != nil {
nodeConfig.NodeSecrets[id] = secret.Data
}
}
}
return nodeConfig, nil
}
// buildInstanceGroupFromCAPI builds an InstanceGroup from a CAPI Machine, for building bootstrap data.
// It builds a minimal instanceGroup, because many fields (e.g. image, machineType, minSize, maxSize)
// are not relevant for building the bootstrap data.
func (s *Server) buildInstanceGroupFromCAPI(ctx context.Context, capiMachine *clusterapi.Machine) (*kops.InstanceGroup, error) {
log := klog.FromContext(ctx)
capiDeploymentName := capiMachine.GetDeploymentName()
if capiDeploymentName == "" {
return nil, fmt.Errorf("CAPI Machine is missing cluster.x-k8s.io/deployment-name label")
}
failureDomain := capiMachine.GetFailureDomain()
if failureDomain == "" {
return nil, fmt.Errorf("CAPI Machine is missing spec.failureDomain")
}
ig := &kops.InstanceGroup{}
ig.Labels = map[string]string{
// kops.LabelClusterName: cluster.Name, // Should not matter
}
ig.Name = capiDeploymentName
// "maxSize": 1, // Should not matter
// "minSize": 1, // Should not matter
// "machineType": "", // Should not matter
// "subnets": // Should not matter
ig.Spec.Zones = []string{failureDomain}
ig.Spec.Role = "Node" // TODO: Support other roles?View on GitHub (pinned to 4c8573c808)
Solutions
- Add cluster.x-k8s.io/deployment-name label to the CAPI Machine
- Fix the MachineTemplate so the label is propagated to Machines
- Recreate the Machine via kOps-managed machine deployment
- Verify CAPI/kOps version compatibility
Example fix
// before
metadata:
labels: {}
// after
metadata:
labels:
cluster.x-k8s.io/deployment-name: my-master-group Defensive patterns
Strategy: validation
Validate before calling
if m.Labels["cluster.x-k8s.io/deployment-name"] == "" {
return fmt.Errorf("machine %s missing deployment-name label", m.Name)
} Type guard
func hasDeploymentName(m *capi.Machine) bool {
return m.GetDeploymentName() != ""
} Prevention
- Ensure kOps-managed MachineTemplates always set cluster.x-k8s.io/deployment-name
- Block label-stripping webhooks/policies on Machine objects
- Audit manually created Machines before enabling node bootstrap
When it happens
Trigger: A bootstrap request arrives from a CAPI Machine whose metadata.labels lack cluster.x-k8s.io/deployment-name, so capiMachine.GetDeploymentName() returns "".
Common situations: Machine template patched by another tool stripping labels; Machine created manually or by an older/foreign controller; kOps managed machinepool templates updated outside kOps.
Related errors
- CAPI Machine is missing spec.failureDomain
- did not find owner for node %q
- error building InstanceGroup from CAPI Machine: %w
- cluster name label %q not yet set
- node identity is required
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/cd2c360a4c001bc2.
Report an issue: GitHub.