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
- Check why the CloudInstance was created with an empty ID — fix the discovery/enumeration code that populated it
- Only call DeleteInstance with CloudInstance objects obtained from the cloud provider's GetCloudGroup/instance listing, not hand-built ones
- Add a pre-call guard skipping instances with empty IDs and log them for investigation
- 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
- Only pass CloudInstance objects produced by the provider's discovery APIs
- Never construct CloudInstance structs by hand in scripts/tests without setting ID
- Log and audit any CloudInstance with empty ID at discovery time
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
- error deleting instance %q: %v
- DIGITALOCEAN_ACCESS_TOKEN is required
- timed out waiting for volume to detach
- unexpected number of network interfaces for instance %q: %v
- unexpected amount of ipv6 prefixes on interface %q: %v
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/8e2fd52f1b14f3cb.
Report an issue: GitHub.