kubernetes/kops · error

spotinst: unexpected instance group type, got: %T

Error message

spotinst: unexpected instance group type, got: %T

What it means

DeleteInstanceGroup dispatches deletion based on the concrete Go type of the Spotinst group (Elastigroup vs LaunchSpec/Ocean). If group.Raw holds a type not covered by the type switch, deletion cannot proceed and this error reports the unexpected concrete type via %T. It indicates a new/unknown Spotinst group type or corrupted data.

Source

Thrown at pkg/resources/spotinst/resources.go:165

	case InstanceGroup:
		{
			var svc InstanceGroupService
			switch obj.Type() {
			case InstanceGroupElastigroup:
				svc = cloud.Elastigroup()
			case InstanceGroupOcean:
				svc = cloud.Ocean()
			}

			return svc.Delete(context.Background(), obj.Id())
		}
	case LaunchSpec:
		{
			return cloud.LaunchSpec().Delete(context.Background(), obj.Id())
		}
	}

	return fmt.Errorf("spotinst: unexpected instance group type, got: %T", group.Raw)
}

// DeleteInstance removes an instance from its instance group.
func DeleteInstance(cloud Cloud, instance *cloudinstances.CloudInstance) error {
	klog.V(2).Infof("Detaching instance %q from instance group: %q",
		instance.ID, instance.CloudInstanceGroup.HumanName)

	group := instance.CloudInstanceGroup
	switch obj := group.Raw.(type) {
	case InstanceGroup:
		{
			var svc InstanceGroupService
			switch obj.Type() {
			case InstanceGroupElastigroup:
				svc = cloud.Elastigroup()
			case InstanceGroupOcean:
				svc = cloud.Ocean()
			}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Upgrade kOps (and its spotinst-sdk-go dependency) to a version whose type switch covers your group type
  2. Check which concrete type appears in the message (%T) and compare with the switch in DeleteInstanceGroup
  3. Migrate the group to a supported type (Elastigroup or LaunchSpec) via the Spotinst console
  4. Patch the type switch to handle the new group type and contribute the fix upstream

Example fix

// before
switch g := group.Raw.(type) {
case ElasticGroup: ...
case LaunchSpec: ...
}
// after — handle Ocean resources too
switch g := group.Raw.(type) {
case ElasticGroup: ...
case LaunchSpec: ...
case ocean.Cluster: return cloud.Ocean().DeleteCluster(context.Background(), g.Id())
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Verify the group type is dispatchable before calling delete
func isDeletableSpotinstGroup(group *spotinst.CloudInstanceGroup) bool {
    switch group.Raw.(type) {
    case spotinst.ElasticGroup, spotinst.LaunchSpec:
        return true
    }
    return false
}

Type guard

func knownSpotinstGroupType(raw interface{}) bool {
    switch raw.(type) {
    case spotinst.ElasticGroup, spotinst.LaunchSpec:
        return true
    default:
        return false
    }
}

Try / catch

if err := spotinst.DeleteInstanceGroup(cloud, group); err != nil {
    if strings.Contains(err.Error(), "unexpected instance group type") {
        klog.Errorf("unsupported spotinst group type; upgrade kOps or delete group %q manually", group.HumanName)
        return errUnsupportedGroup
    }
    return err
}

Prevention

When it happens

Trigger: DeleteGroup → DeleteInstanceGroup (pkg/resources/spotinst/resources.go:165) receives a group whose Raw field is neither ElasticGroup nor LaunchSpec — e.g. a new Spotinst product (Ocean cluster type) added upstream but the kOps type switch not updated, or a mismatched SDK version returning a new struct.

Common situations: kOps and spotinst-sdk-go version drift after upgrade; cluster contains a mixture of Ocean and Elastigroup resources and the code path only handles the legacy types; manual state edits producing wrong Raw payloads.

Related errors


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