kubernetes/kops · error

error deleting subnet

Error message

error deleting subnet: %v

What it means

deleteSubnet deletes a Neutron subnet by ID inside a RetryWithBackoff(deleteBackoff) loop, tolerating 404 (already gone) via isNotFound. Any other failure is wrapped as "error deleting subnet: %v" and retried until backoff is exhausted. This typically means the subnet still has dependents or the API rejected the delete.

Solutions

  1. Check the wrapped error for 409 conflict and delete dependent ports/router interfaces first: `openstack port list --subnet <id>`,`openstack router remove subnet`
  2. Ensure no instances/load balancers still use the subnet
  3. Retry `kops delete cluster` after dependents are removed
  4. Verify project RBAC allows subnet deletion
Defensive patterns

Strategy: validation

Validate before calling

// Ensure no ports remain on the subnet before delete
out, err := exec.Command("openstack", "port", "list", "--subnet", subnetID, "-f", "value", "-c", "ID").Output()
if err == nil && len(strings.TrimSpace(string(out))) > 0 {
	log.Fatalf("subnet %s still has ports: %s", subnetID, string(out))
}

Try / catch

err := deleteSubnet(cloud, subnetID)
if err != nil {
	if strings.Contains(err.Error(), "409") || strings.Contains(err.Error(), "conflict") {
		// detach router interfaces / delete ports, then retry
	}
	return err
}

Prevention

When it happens

Trigger: Subnet has attached ports (instances, routers, LBs) so Neutron returns 409 conflict; RBAC denies deletion; or Neutron is unhealthy.

Common situations: Tearing down a cluster where VMs/ports were not yet deleted, a router interface still attached to the subnet, or manual resources sharing the subnet blocking kops destroy.

Related errors


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

Appendix: source

Thrown at upup/pkg/fi/cloudup/openstack/subnet.go:113

	})
	if err != nil {
		return s, err
	} else if done {
		return s, nil
	} else {
		return s, wait.ErrWaitTimeout
	}
}

func (c *openstackCloud) DeleteSubnet(subnetID string) error {
	return deleteSubnet(c, subnetID)
}

func deleteSubnet(c OpenstackCloud, subnetID string) error {
	done, err := vfs.RetryWithBackoff(deleteBackoff, func() (bool, error) {
		err := subnets.Delete(context.TODO(), c.NetworkingClient(), subnetID).ExtractErr()
		if err != nil && !isNotFound(err) {
			return false, fmt.Errorf("error deleting subnet: %v", err)
		}
		if isNotFound(err) {
			return true, nil
		}
		return false, nil
	})
	if err != nil {
		return err
	} else if done {
		return nil
	} else {
		return wait.ErrWaitTimeout
	}
}

func (c *openstackCloud) GetExternalSubnet() (subnet *subnets.Subnet, err error) {
	return getExternalSubnet(c, c.extSubnetName)
}

View on GitHub (pinned to 4c8573c808)