kubernetes/kops · error

unhandled role %q

Error message

unhandled role %q

What it means

The function that recommends a default machine image/instance-type path per instance group has an exhaustive switch on ig.Spec.Role (kops InstanceGroupRole: ControlPlane, Node, Bastion, etc.). When a role value falls outside the handled cases, it returns 'unhandled role %q'. This guards against new or invalid roles being silently assigned wrong defaults.

Source

Thrown at upup/pkg/fi/cloudup/awsup/aws_cloud.go:1994

	case ig.Spec.Role.HasNode() || ig.Spec.Role.IsControlPlaneType():
		// t3.medium is the cheapest instance with 4GB of mem, unlimited by default, fast and has decent network
		// c5.large and c4.large are a good second option in case t3.medium is not available in the AZ
		candidates = []ec2types.InstanceType{
			ec2types.InstanceTypeT3Medium,
			ec2types.InstanceTypeC5Large,
			ec2types.InstanceTypeC4Large,
			ec2types.InstanceTypeT4gMedium,
		}

	case ig.Spec.Role.HasBastion():
		candidates = []ec2types.InstanceType{
			ec2types.InstanceTypeT3Micro,
			ec2types.InstanceTypeT2Micro,
			ec2types.InstanceTypeT4gMicro,
		}

	default:
		return "", fmt.Errorf("unhandled role %q", ig.Spec.Role)
	}

	imageArch := ec2types.ArchitectureTypeX8664
	if imageInfo, err := c.ResolveImage(ig.Spec.Image); err == nil {
		imageArch = ec2types.ArchitectureType(imageInfo.Architecture)
	}

	// Find the AZs the InstanceGroup targets
	igZones, err := model.FindZonesForInstanceGroup(cluster, ig)
	if err != nil {
		return "", err
	}
	igZonesSet := sets.NewString(igZones...)

	// TODO: Validate that instance type exists in all AZs, but skip AZs that don't support any VPC stuff
	var reasons []string
	for _, instanceType := range candidates {
		if strings.HasPrefix(string(instanceType), "t4g") {

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Check the instance group's role value: kops get ig <name> -o yaml and confirm spec.role is one of ControlPlane, Node, Bastion (or apiserver-managed equivalents).
  2. Fix typos/casing in the cluster spec and run kops update cluster.
  3. Align kops versions — upgrade or downgrade so the binary and cluster spec use the same role vocabulary.
  4. If a genuinely new role was added upstream, update the switch statement to handle it (patch aws_cloud.go).

Example fix

// before
case kops.InstanceGroupRoleNode:
    ...
default:
    return "", fmt.Errorf("unhandled role %q", ig.Spec.Role)
// after: handle the new role
case kops.InstanceGroupRoleControlPlane, kops.InstanceGroupRoleNode, kops.InstanceGroupRoleBastion:
    ...
Defensive patterns

Strategy: validation

Validate before calling

valid := map[kops.InstanceGroupRole]bool{
    kops.InstanceGroupRoleControlPlane: true,
    kops.InstanceGroupRoleNode:         true,
    kops.InstanceGroupRoleBastion:      true,
}
if !valid[ig.Spec.Role] {
    return fmt.Errorf("invalid instance group role %q; must be ControlPlane, Node, or Bastion", ig.Spec.Role)
}

Type guard

func isKnownInstanceGroupRole(r kops.InstanceGroupRole) bool {
    switch r {
    case kops.InstanceGroupRoleControlPlane, kops.InstanceGroupRoleNode, kops.InstanceGroupRoleBastion:
        return true
    }
    return false
}

Prevention

When it happens

Trigger: An instance group's spec.role is a value the switch doesn't handle — e.g. a kops version where a new role (like 'APIServer' or 'WarmPool'-related roles) exists but this code predates it, a typo'd/empty role in a hand-edited cluster spec, or a role that only applies to some clouds being used on AWS.

Common situations: Hand-editing the cluster manifest and setting role to an invalid lowercase string; using a newer kops CLI with an older controller/library build (or vice versa); copying an instance group from another provider (e.g. GCE-specific role) into an AWS cluster.

Related errors


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