{"record":{"id":"cd2c360a4c001bc2","repo":"kubernetes/kops","slug":"capi-machine-is-missing-cluster-x-k8s-io-deploymen","errorCode":null,"errorMessage":"CAPI Machine is missing cluster.x-k8s.io/deployment-name label","messagePattern":"CAPI Machine is missing cluster\\.x-k8s\\.io/deployment-name label","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/kops-controller/pkg/server/node_config.go","lineNumber":125,"sourceCode":"\t\t\t}\n\t\t\tif secret != nil && secret.Data != nil {\n\t\t\t\tnodeConfig.NodeSecrets[id] = secret.Data\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nodeConfig, nil\n}\n\n// buildInstanceGroupFromCAPI builds an InstanceGroup from a CAPI Machine, for building bootstrap data.\n// It builds a minimal instanceGroup, because many fields (e.g. image, machineType, minSize, maxSize)\n// are not relevant for building the bootstrap data.\nfunc (s *Server) buildInstanceGroupFromCAPI(ctx context.Context, capiMachine *clusterapi.Machine) (*kops.InstanceGroup, error) {\n\tlog := klog.FromContext(ctx)\n\n\tcapiDeploymentName := capiMachine.GetDeploymentName()\n\tif capiDeploymentName == \"\" {\n\t\treturn nil, fmt.Errorf(\"CAPI Machine is missing cluster.x-k8s.io/deployment-name label\")\n\t}\n\tfailureDomain := capiMachine.GetFailureDomain()\n\tif failureDomain == \"\" {\n\t\treturn nil, fmt.Errorf(\"CAPI Machine is missing spec.failureDomain\")\n\t}\n\n\tig := &kops.InstanceGroup{}\n\tig.Labels = map[string]string{\n\t\t// kops.LabelClusterName: cluster.Name, // Should not matter\n\t}\n\tig.Name = capiDeploymentName\n\n\t// \"maxSize\": 1, // Should not matter\n\t// \"minSize\": 1, // Should not matter\n\t// \"machineType\": \"\", // Should not matter\n\t// \"subnets\": // Should not matter\n\tig.Spec.Zones = []string{failureDomain}\n\tig.Spec.Role = \"Node\" // TODO: Support other roles?","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/cmd/kops-controller/pkg/server/node_config.go#L107-L143","documentation":"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.","triggerScenarios":"A bootstrap request arrives from a CAPI Machine whose metadata.labels lack cluster.x-k8s.io/deployment-name, so capiMachine.GetDeploymentName() returns \"\".","commonSituations":"Machine template patched by another tool stripping labels; Machine created manually or by an older/foreign controller; kOps managed machinepool templates updated outside kOps.","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"],"exampleFix":"// before\nmetadata:\n  labels: {}\n// after\nmetadata:\n  labels:\n    cluster.x-k8s.io/deployment-name: my-master-group","handlingStrategy":"validation","validationCode":"if m.Labels[\"cluster.x-k8s.io/deployment-name\"] == \"\" {\n    return fmt.Errorf(\"machine %s missing deployment-name label\", m.Name)\n}","typeGuard":"func hasDeploymentName(m *capi.Machine) bool {\n    return m.GetDeploymentName() != \"\"\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["go","capi","kubernetes","labels","bootstrap"],"backgroundTag":"missing-required-label","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}