kubernetes/kops · error

error deleting DhcpOptions %q: %v

Error message

error deleting DhcpOptions %q: %v

What it means

kOps wraps failures from the EC2 DeleteDhcpOptions API. NotFound is treated as already-deleted and dependency violations are returned bare for retry; anything else is wrapped with the DHCP options set ID. The DHCP options set could not be deleted for another reason.

Source

Thrown at pkg/resources/aws/aws.go:949

func DeleteDhcpOptions(cloud fi.Cloud, r *resources.Resource) error {
	ctx := context.TODO()
	c := cloud.(awsup.AWSCloud)

	id := r.ID

	klog.V(2).Infof("Deleting EC2 DhcpOptions %q", id)
	request := &ec2.DeleteDhcpOptionsInput{
		DhcpOptionsId: &id,
	}
	_, err := c.EC2().DeleteDhcpOptions(ctx, request)
	if err != nil {
		if awsup.AWSErrorCode(err) == "InvalidDhcpOptionsID.NotFound" {
			klog.V(2).Infof("Got InvalidDhcpOptionsID.NotFound error deleting DhcpOptions %q; will treat as already-deleted", id)
			return nil
		} else if IsDependencyViolation(err) {
			return err
		}
		return fmt.Errorf("error deleting DhcpOptions %q: %v", id, err)
	}
	return nil
}

func ListDhcpOptions(cloud fi.Cloud, vpcID, clusterName string) ([]*resources.Resource, error) {
	dhcpOptions, err := DescribeDhcpOptions(cloud)
	if err != nil {
		return nil, err
	}

	var resourceTrackers []*resources.Resource

	for _, o := range dhcpOptions {
		resourceTracker := &resources.Resource{
			Name:    FindName(o.Tags),
			ID:      aws.ToString(o.DhcpOptionsId),
			Type:    "dhcp-options",
			Deleter: DeleteDhcpOptions,

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Confirm current state with `aws ec2 describe-dhcp-options --dhcp-options-ids <id>`; if absent, treat as deleted and continue
  2. Wait for retry — if the real cause is a dependency violation, kOps' caller retries until the VPC is deleted
  3. Grant the identity ec2:DeleteDhcpOptions in IAM
  4. Retry the whole kOps delete; the flow is idempotent

Example fix

// before
return fmt.Errorf("error deleting DhcpOptions %q: %v", id, err)
// after (caller side)
if strings.Contains(err.Error(), "Throttling") {
	time.Sleep(backoff)
	return retry()
}
Defensive patterns

Strategy: retry

Validate before calling

// check existence before delete
out, err := c.EC2().DescribeDhcpOptions(ctx, &ec2.DescribeDhcpOptionsInput{
	DhcpOptionsIds: []string{id},
})
if err != nil { return err }
if len(out.DhcpOptions) == 0 { return nil } // already gone

Type guard

func dhcpOptionsExists(out *ec2.DescribeDhcpOptionsOutput) bool {
	return out != nil && len(out.DhcpOptions) > 0
}

Try / catch

if err != nil {
	switch {
	case awsup.AWSErrorCode(err) == "InvalidDhcpOptionsID.NotFound":
		return nil
	case awserrors.IsDependencyViolation(err):
		return backoff.Retry(func() error { return retryDelete() }, expBackoff)
	default:
		return fmt.Errorf("error deleting DhcpOptions %q: %v", id, err)
	}
}

Prevention

When it happens

Trigger: EC2 DeleteDhcpOptions returns an error that is neither InvalidDhcpOptionsID.NotFound nor a dependency violation: throttling, auth failure, or an invalid options-set ID format.

Common situations: Bulk cluster teardown hitting EC2 rate limits; IAM policy missing ec2:DeleteDhcpOptions; stale resource trackers referencing a set already removed by another cleanup run.

Related errors


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