{"record":{"id":"2909f3866c48e14f","repo":"kubernetes/kops","slug":"unhandled-instancegroup-role-q","errorCode":null,"errorMessage":"unhandled instanceGroup role %q","messagePattern":"unhandled instanceGroup role %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/nodelabels/builder.go","lineNumber":60,"sourceCode":")\n\n// BuildNodeLabels returns the node labels for the specified instance group\n// This moved from the kubelet to a central controller in kubernetes 1.16\nfunc BuildNodeLabels(cluster *api.Cluster, instanceGroup *api.InstanceGroup) (map[string]string, error) {\n\tisControlPlane := false\n\tisAPIServer := false\n\tisNode := false\n\tswitch {\n\tcase instanceGroup.Spec.Role.HasControlPlane():\n\t\tisControlPlane = true\n\tcase instanceGroup.Spec.Role.HasAPIServer():\n\t\tisAPIServer = true\n\tcase instanceGroup.Spec.Role.HasNode():\n\t\tisNode = true\n\tcase instanceGroup.Spec.Role.HasBastion():\n\t\t// no labels to add\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unhandled instanceGroup role %q\", instanceGroup.Spec.Role)\n\t}\n\n\t// Merge KubeletConfig for NodeLabels\n\tc := &api.KubeletConfigSpec{}\n\tif isControlPlane {\n\t\treflectutils.JSONMergeStruct(c, cluster.Spec.ControlPlaneKubelet)\n\t} else {\n\t\treflectutils.JSONMergeStruct(c, cluster.Spec.Kubelet)\n\t}\n\n\tif instanceGroup.Spec.Kubelet != nil {\n\t\treflectutils.JSONMergeStruct(c, instanceGroup.Spec.Kubelet)\n\t}\n\n\tnodeLabels := c.NodeLabels\n\n\tif isAPIServer || isControlPlane {\n\t\tif nodeLabels == nil {","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/nodelabels/builder.go#L42-L78","documentation":"BuildNodeLabels maps the InstanceGroup role to node labels. Roles are matched against control-plane, node, and bastion; any other/unset role hits the default branch and throws. This is a role-dispatch exhaustiveness guard.","triggerScenarios":"An InstanceGroup whose Spec.Role is empty or not one of Master/ControlPlane/Node/Bastion is passed to BuildNodeLabels (via CloudTagsForInstanceGroup, PopulateInstanceGroupSpec, etc.).","commonSituations":"Hand-edited cluster YAML missing the role field on an instance group; JSON/YAML typo in role name; older/newer cluster spec version with a role not supported by this kOps build.","solutions":["Set instanceGroup.spec.role to a valid value: ControlPlane, Master (legacy), Node, or Bastion","Re-run kops get ig / validate to ensure the spec parses into a known role","Upgrade/downgrade kOps so the role value matches a supported version of the schema"],"exampleFix":"// before\nspec:\n  role: \"\"\n// after\nspec:\n  role: Node","handlingStrategy":"validation","validationCode":"func validRole(r kops.InstanceGroupRole) bool {\n    return r == kops.InstanceGroupRoleControlPlane || r == kops.InstanceGroupRoleMaster ||\n        r == kops.InstanceGroupRoleNode || r == kops.InstanceGroupRoleBastion\n}\nif !validRole(ig.Spec.Role) {\n    return fmt.Errorf(\"ig %s has invalid role %q\", ig.Name, ig.Spec.Role)\n}","typeGuard":"func hasKnownRole(ig *api.InstanceGroup) bool {\n    return ig != nil && validRole(ig.Spec.Role)\n}","tryCatchPattern":null,"preventionTips":["Always set spec.role explicitly in InstanceGroup manifests","Run kops validate/replace on manifests before applying","Keep role enums in sync with the kOps version in use"],"tags":["instancegroup","role","labels","config"],"backgroundTag":"unhandled-enum-value","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"}