kubernetes/kops · error

spotinst: found multiple role tags %q vs %q

Error message

spotinst: found multiple role tags %q vs %q

What it means

While mapping AWS tags on an instance to an instance-group role (in the spotinst elastigroup task's tag-discovery path), kOps finds more than one tag prefixed with CloudTagInstanceGroupRolePrefix carrying different role suffixes. The role suffix "master" is normalized to "control-plane" before comparison. This indicates contradictory role tags on the resource.

Source

Thrown at upup/pkg/fi/cloudup/spotinsttasks/elastigroup.go:1529

	// Image.
	if e.ImageID != nil {
		image, err := resolveImage(cloud, fi.ValueOf(e.ImageID))
		if err != nil {
			return err
		}
		tf.ImageID = image.ImageId
	}

	var role string
	for key := range e.Tags {
		if strings.HasPrefix(key, awstasks.CloudTagInstanceGroupRolePrefix) {
			suffix := strings.TrimPrefix(key, awstasks.CloudTagInstanceGroupRolePrefix)
			if suffix == "master" {
				suffix = "control-plane"
			}
			if role != "" && role != suffix {
				return fmt.Errorf("spotinst: found multiple role tags %q vs %q", role, suffix)
			}
			role = suffix
		}
	}

	// Security groups.
	if e.SecurityGroups != nil {
		for _, sg := range e.SecurityGroups {
			tf.SecurityGroups = append(tf.SecurityGroups, sg.TerraformLink())
			if role != "" {
				if err := t.AddOutputVariableArray(role+"_security_groups", sg.TerraformLink()); err != nil {
					return err
				}
			}
		}
	}

	// User data.

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Inspect the resource's AWS tags and delete the stale duplicate role tag (e.g. the old "master" tag) so exactly one role tag remains.
  2. Re-run `kops update cluster` to let kOps rewrite tags consistently.
  3. If tags were manually edited, restore the tag set kOps expects for that instance group.
  4. For post-1.24 clusters, ensure no legacy kubernetes.io/cluster/...-role-master tags are copied onto spotinst-managed resources.

Example fix

// before: both tags on the instance
KubernetesCluster/example-cluster-role-master, value=control-plane
KubernetesCluster/example-cluster-role-control-plane, value=control-plane
// after: single normalized tag
KubernetesCluster/example-cluster-role-control-plane, value=control-plane
Defensive patterns

Strategy: validation

Validate before calling

// enforce a single role tag per resource before reconciliation
role := ""
for key := range tags {
    if strings.HasPrefix(key, awstasks.CloudTagInstanceGroupRolePrefix) {
        suffix := strings.TrimPrefix(key, awstasks.CloudTagInstanceGroupRolePrefix)
        if suffix == "master" { suffix = "control-plane" }
        if role != "" && role != suffix {
            return fmt.Errorf("conflicting role tags %q vs %q — remove the legacy tag", role, suffix)
        }
        role = suffix
    }
}

Try / catch

role, err := roleFromTags(tags)
if err != nil {
    klog.Warningf("skipping resource with conflicting role tags: %v", err)
    continue // skip instead of aborting the whole reconciliation
}

Prevention

When it happens

Trigger: The iteration over tags encounters two keys like KubernetesCluster/<cluster>-role-control-plane and ...-role-master (or node vs control-plane) on the same object with differing suffixes, so role != "" && role != suffix fires.

Common situations: Cluster upgraded from kOps versions that used "master" tags to the newer "control-plane" tag where both tags linger on an instance/security group; hand-edited tags in the AWS console; copied tags between instance groups.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/5d337b918adc4b75. Report an issue: GitHub.