kubernetes/kops · error

error deleting network %s: %v

Error message

error deleting network %s: %v

What it means

Thrown by deleteNetwork when Compute Networks().Delete fails with any error except NotFound. The cluster VPC network could not be deleted; typically because dependent resources (subnets, firewall rules, VPN, peering) still exist.

Source

Thrown at pkg/resources/gce/gce.go:1260

}

func deleteNetwork(cloud fi.Cloud, r *resources.Resource) error {
	c := cloud.(gce.GCECloud)
	o := r.Obj.(*compute.Network)

	klog.V(2).Infof("deleting GCE network %s", o.SelfLink)
	u, err := gce.ParseGoogleCloudURL(o.SelfLink)
	if err != nil {
		return err
	}

	op, err := c.Compute().Networks().Delete(u.Project, u.Name)
	if err != nil {
		if gce.IsNotFound(err) {
			klog.Infof("Network not found, assuming deleted: %q", o.SelfLink)
			return nil
		}
		return fmt.Errorf("error deleting network %s: %v", o.SelfLink, err)
	}

	return c.WaitForOp(op)
}

func (d *clusterDiscoveryGCE) matchesClusterName(name string) bool {
	// Names could have hypens in them, so really there is no limit.
	// 8 hyphens feels like enough for any "reasonable" name
	maxParts := 8

	return d.matchesClusterNameMultipart(name, maxParts)
}

// matchesClusterNameMultipart checks if the name could have been generated by our cluster
// considering all the prefixes separated by `-`.  maxParts limits the number of parts we consider.
func (d *clusterDiscoveryGCE) matchesClusterNameMultipart(name string, maxParts int) bool {
	tokens := strings.Split(name, "-")

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Delete remaining dependent resources first: subnetworks, firewall rules, routes, VPN tunnels, peerings.
  2. Grant compute.networkAdmin so networks.delete is permitted.
  3. Retry `kops delete cluster` after cleanup — it is idempotent (NotFound tolerated).
  4. For shared VPC (XPN) networks, detach/fix the host-project attachment before deleting.
  5. Clean up manually with `gcloud compute networks delete NAME` if kops state no longer tracks them.

Example fix

// before
return fmt.Errorf("error deleting network %s: %v", o.SelfLink, err)
// after
if apiErr, ok := err.(*googleapi.Error); ok && apiErr.Code == 400 && strings.Contains(apiErr.Message, "in use") {
	return fmt.Errorf("network %s still has dependent resources (subnets/firewall rules); delete them first: %w", o.SelfLink, err)
}
return fmt.Errorf("error deleting network %s: %w", o.SelfLink, err)
Defensive patterns

Strategy: try-catch

Validate before calling

// before deleting the network, confirm no dependents remain
if subnets, _ := listSubnetsInNetwork(project, networkName); len(subnets) > 0 {
	return fmt.Errorf("network %s still has %d subnets", networkName, len(subnets))
}

Type guard

func isNetworkInUse(err error) bool {
	ge, ok := err.(*googleapi.Error)
	return ok && ge.Code == 400 && strings.Contains(ge.Message, "in use")
}

Try / catch

op, err := c.Compute().Networks().Delete(u.Project, u.Name)
if err != nil {
	if gce.IsNotFound(err) {
		return nil
	}
	if isNetworkInUse(err) {
		return fmt.Errorf("delete dependent subnets/firewall rules first: %w", err)
	}
	return fmt.Errorf("error deleting network %s: %w", o.SelfLink, err)
}
return c.WaitForOp(op)

Prevention

When it happens

Trigger: Networks().Delete(project, name) returns 400 failedPrecondition ('network is in use' by subnetworks/firewall rules/routes), 403 permission denied, 409 concurrent operation, or transient 5xx.

Common situations: Cluster deletion order left subnets/firewall rules behind; peering or shared VPC attachments hold the network; IAM lacks networks.delete; earlier deletion steps failed leaving dependents.

Related errors


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