kubernetes/kops · error

id was not set on CloudInstance: %v

Error message

id was not set on CloudInstance: %v

What it means

deleteInstance() requires the CloudInstance struct to carry a non-empty EC2 instance ID because it is used verbatim in the ec2.TerminateInstances call. When i.ID is empty, kOps cannot terminate anything and returns this error instead of issuing an invalid API call. It indicates the CloudInstance was constructed from incomplete cloud data (e.g. an ASG member whose instance ID never got populated).

Source

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

func (c *awsCloudImplementation) DeregisterInstance(i *cloudinstances.CloudInstance) error {
	ctx := context.TODO()

	if c.spotinst != nil || i.CloudInstanceGroup.InstanceGroup.Spec.Manager == kops.InstanceManagerKarpenter {
		return nil
	}

	err := deregisterInstance(ctx, c, i)
	if err != nil {
		return fmt.Errorf("failed to deregister instance from loadBalancer before terminating: %v", err)
	}

	return nil
}

func deleteInstance(ctx context.Context, c AWSCloud, i *cloudinstances.CloudInstance) error {
	id := i.ID
	if id == "" {
		return fmt.Errorf("id was not set on CloudInstance: %v", i)
	}

	request := &ec2.TerminateInstancesInput{
		InstanceIds: []string{id},
	}

	if _, err := c.EC2().TerminateInstances(ctx, request); err != nil {
		if AWSErrorCode(err) == "InvalidInstanceID.NotFound" {
			klog.V(2).Infof("Got InvalidInstanceID.NotFound error deleting instance %q; will treat as already-deleted", id)
		} else {
			return fmt.Errorf("error deleting instance %q: %v", id, err)
		}
	}

	klog.V(8).Infof("deleted aws ec2 instance %q", id)

	return nil
}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Check why the CloudInstance was created with an empty ID — fix the discovery/enumeration code that populated it
  2. Only call DeleteInstance with CloudInstance objects obtained from the cloud provider's GetCloudGroup/instance listing, not hand-built ones
  3. Add a pre-call guard skipping instances with empty IDs and log them for investigation
  4. Upgrade kOps — if caused by an upstream enumeration bug, a newer version may already fix it

Example fix

// before
for _, i := range group.CloudInstances {
	_ = cloud.DeleteInstance(i)
}
// after
for _, i := range group.CloudInstances {
	if i.ID == "" {
		klog.Warningf("skipping instance with no ID in group %s", group.HumanName)
		continue
	}
	_ = cloud.DeleteInstance(i)
}
Defensive patterns

Strategy: validation

Validate before calling

if inst == nil || inst.ID == "" {
	klog.Warningf("skipping CloudInstance with empty ID: %+v", inst)
	return nil
}
_ = cloud.DeleteInstance(inst)

Type guard

func hasID(i *cloudinstances.CloudInstance) bool {
	return i != nil && i.ID != ""
}

Try / catch

if err := cloud.DeleteInstance(inst); err != nil {
	if strings.Contains(err.Error(), "id was not set") {
		klog.Warningf("instance record incomplete (%v); refreshing group state", err)
		return refreshAndRetry(inst)
	}
	return err
}

Prevention

When it happens

Trigger: DeleteInstance is invoked on a cloudinstances.CloudInstance whose ID field is "" — typically when instance discovery populated the group but not the individual instance record, or code built a CloudInstance manually without setting ID.

Common situations: Bugs in cloud instance enumeration; instances in a partially-created state; caller-supplied CloudInstance structs built by hand in custom tooling or tests without setting ID; races where the ASG reports a member before its instance ID is known.

Related errors


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