kubernetes/kops · error

could not delete port %q: %v

Error message

could not delete port %q: %v

What it means

Wrapped error returned while deleting OpenStack Neutron ports belonging to an instance group during cluster teardown. kOps enumerates the group's ports and calls DeletePort for each; if the Neutron API rejects or fails a single port deletion, the whole operation aborts with this message wrapping the port ID and underlying error.

Source

Thrown at upup/pkg/fi/cloudup/openstack/cloud.go:635

}

func deletePorts(c OpenstackCloud, instanceGroupName string, clusterName string) error {
	tags := []string{
		fmt.Sprintf("%s=%s", TagClusterName, clusterName),
		fmt.Sprintf("%s=%s", TagKopsInstanceGroup, instanceGroupName),
	}

	ports, err := c.ListPorts(ports.ListOpts{Tags: strings.Join(tags, ",")})
	if err != nil {
		return fmt.Errorf("could not list ports %v", err)
	}

	for _, port := range ports {
		klog.V(2).Infof("Delete port '%s' (%s)", port.Name, port.ID)
		err := c.DeletePort(port.ID)

		if err != nil {
			return fmt.Errorf("could not delete port %q: %v", port.ID, err)
		}
	}

	return nil
}

func deleteGroup(c OpenstackCloud, g *cloudinstances.CloudInstanceGroup) error {
	cluster := g.Raw.(*kops.Cluster)
	allInstances, err := c.ListInstances(servers.ListOpts{
		Name: fmt.Sprintf("^%s", g.InstanceGroup.Name),
	})
	if err != nil {
		return err
	}

	instances := []servers.Server{}
	for _, instance := range allInstances {
		if !InstanceInClusterAndIG(instance, cluster.Name, g.InstanceGroup.Name) {

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Check the wrapped %v error for the HTTP status; if 404, the port is already gone and the group cleanup can be re-run safely
  2. Ensure instances in the group are deleted before ports (kOps deletes instances first in deleteInstanceGroup)
  3. Re-run kops delete after the conflict clears; 409 errors are usually transient while resources detach
  4. Verify OS_* cloud credentials and Neutron endpoint reachability
Defensive patterns

Strategy: retry

Validate before calling

// before teardown
ports, _ := c.ListPorts(network.ListOpts{})
for _, p := range ports {
    if attached(p.DeviceID) { klog.Infof("port %s still attached; delete instances first", p.ID) }
}

Try / catch

// Go: check wrapped error and classify
if err := c.DeletePort(port.ID); err != nil {
    var gErr gophercloud.ErrUnexpectedResponseCode
    if errors.As(err, &gErr) && gErr.Actual == 404 { continue /* already gone */ }
    return fmt.Errorf("could not delete port %q: %v", port.ID, err)
}

Prevention

When it happens

Trigger: DeletePort(port.ID) returns a non-nil error, typically a 404 (port already gone), 409 (port in use by an active instance/DHCP), or a network/auth failure against the Neutron endpoint.

Common situations: Port already deleted by a parallel cleanup or manual run; instance still holding the port (must delete instance first); Neutron quota or connectivity issues; stale credentials after Keystone token expiry.

Related errors


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