{"record":{"id":"6ce2cfe6f9a71cbb","repo":"kubernetes/kops","slug":"capi-machine-is-missing-spec-failuredomain","errorCode":null,"errorMessage":"CAPI Machine is missing spec.failureDomain","messagePattern":"CAPI Machine is missing spec\\.failureDomain","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/kops-controller/pkg/server/node_config.go","lineNumber":129,"sourceCode":"\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?\n\t// The machine image is chosen by the CAPI infrastructure provider and is not used for\n\t// nodeup config generation; the placeholder avoids resolving a default from the channel.\n\tig.Spec.Image = \"placeholder-image\"\n","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/cmd/kops-controller/pkg/server/node_config.go#L111-L147","documentation":"The CAPI Machine must declare spec.failureDomain so kOps can place it in the right zone/failure domain when reconstructing the InstanceGroup. This error is thrown when GetFailureDomain() returns an empty string.","triggerScenarios":"A bootstrap request from a CAPI Machine whose spec.failureDomain is unset or empty.","commonSituations":"Machine created directly (not by a kOps-generated MachineDeployment) without failureDomain; cloud provider doesn't populate it; template authored manually omitting spec.failureDomain.","solutions":["Set spec.failureDomain on the CAPI Machine (e.g. the AZ/zone)","Update the MachineDeployment/MachineSet template to include failureDomain","Recreate the Machine through the kOps-managed machine deployment"],"exampleFix":"// before\nspec: {}\n// after\nspec:\n  failureDomain: us-east-1a","handlingStrategy":"validation","validationCode":"if m.Spec.FailureDomain == nil || *m.Spec.FailureDomain == \"\" {\n    return fmt.Errorf(\"machine %s missing spec.failureDomain\", m.Name)\n}","typeGuard":"func hasFailureDomain(m *capi.Machine) bool {\n    return m.GetFailureDomain() != \"\"\n}","tryCatchPattern":null,"preventionTips":["Set spec.failureDomain in MachineDeployment templates","Create Machines only through kOps-generated MachineDeployments","Validate machine manifests with admission policies"],"tags":["go","capi","kubernetes","bootstrap"],"backgroundTag":"missing-spec-field","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}