{"record":{"id":"23508ef85591c866","repo":"kubernetes/kops","slug":"spotinst-found-multiple-role-tags-q-vs-q-23508e","errorCode":null,"errorMessage":"spotinst: found multiple role tags %q vs %q","messagePattern":"spotinst: found multiple role tags %q vs %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/spotinsttasks/ocean.go","lineNumber":1216,"sourceCode":"\n\t// Image.\n\tif e.ImageID != nil {\n\t\timage, err := resolveImage(cloud, fi.ValueOf(e.ImageID))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttf.ImageID = image.ImageId\n\t}\n\n\tvar role string\n\tfor key := range e.Tags {\n\t\tif strings.HasPrefix(key, awstasks.CloudTagInstanceGroupRolePrefix) {\n\t\t\tsuffix := strings.TrimPrefix(key, awstasks.CloudTagInstanceGroupRolePrefix)\n\t\t\tif role == \"master\" {\n\t\t\t\trole = \"control-plane\"\n\t\t\t}\n\t\t\tif role != \"\" && role != suffix {\n\t\t\t\treturn fmt.Errorf(\"spotinst: found multiple role tags %q vs %q\", role, suffix)\n\t\t\t}\n\t\t\trole = suffix\n\t\t}\n\t}\n\n\t// Security groups.\n\tif e.SecurityGroups != nil {\n\t\tfor _, sg := range e.SecurityGroups {\n\t\t\ttf.SecurityGroups = append(tf.SecurityGroups, sg.TerraformLink())\n\t\t\tif role != \"\" {\n\t\t\t\tif err := t.AddOutputVariableArray(role+\"_security_groups\", sg.TerraformLink()); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Monitoring.","sourceCodeStart":1198,"sourceCodeEnd":1234,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/spotinsttasks/ocean.go#L1198-L1234","documentation":"While rendering Terraform for a Spotinst Ocean, kOps scans the task's tags for `kops.k8s.io/instance_group_role` role tags and expects at most one distinct role suffix. If two tags map to different roles (e.g. both a master and a node role tag), it cannot decide which role the Ocean represents and throws this error.","triggerScenarios":"The cluster spec's tags on the Spotinst task carry the CloudTagInstanceGroupRolePrefix prefix with more than one distinct suffix (e.g. 'master' and 'node'), typically from copy-pasting tags between instance groups or merging cluster specs.","commonSituations":"Hand-edited cluster.yaml where role tags from multiple instance groups were combined onto one resource; automated tooling injecting extra `kops.k8s.io/instance_group_role*` tags.","solutions":["Edit the cluster spec and remove the duplicate/conflicting `kops.k8s.io/instance_group_role*` tag so only one role remains per Ocean.","Re-run `kops update cluster` after `kops replace -f cluster.yaml` to regenerate Terraform with a single role tag.","If roles were merged intentionally, split the resources so each Ocean/instance group has its own role tag."],"exampleFix":"// before (cluster spec tags)\nkops.k8s.io/instance_group_role_master: \"\"\nkops.k8s.io/instance_group_role_node: \"\"\n// after\nkops.k8s.io/instance_group_role_node: \"\"","handlingStrategy":"validation","validationCode":"// ensure only one distinct role tag is present\nroles := map[string]bool{}\nfor k := range tags {\n    if strings.HasPrefix(k, awstasks.CloudTagInstanceGroupRolePrefix) {\n        roles[strings.TrimPrefix(k, awstasks.CloudTagInstanceGroupRolePrefix)] = true\n    }\n}\nif len(roles) > 1 { return fmt.Errorf(\"multiple role tags: %v\", roles) }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never hand-merge tags from multiple instance groups onto one Spotinst task.","Treat `kops.k8s.io/instance_group_role*` tags as kOps-managed; do not edit them manually.","Run `kops update cluster --dry-run` in CI to catch tag conflicts before apply."],"tags":["spotinst","terraform","tags","config-validation"],"backgroundTag":"conflicting-role-tags","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"}