kubernetes/kops · error

error deleting FirewallRule %s: %v

Error message

error deleting FirewallRule %s: %v

What it means

Wraps a failure from Compute Firewalls().Delete in deleteFirewallRule during cluster teardown. NotFound is handled as already-deleted success, so this surfaces genuine delete failures: permission denied, rate limits, server errors, or firewall rules locked by other GCP features. Message includes the firewall rule's SelfLink and the raw error.

Source

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

// deleteFirewallRule is the helper function to delete a Resource for a Firewall object
func deleteFirewallRule(cloud fi.Cloud, r *resources.Resource) error {
	c := cloud.(gce.GCECloud)
	t := r.Obj.(*compute.Firewall)

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

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

	return c.WaitForOp(op)
}

func (d *clusterDiscoveryGCE) listRoutes(ctx context.Context, resourceMap map[string]*resources.Resource) ([]*resources.Resource, error) {
	c := d.gceCloud

	var resourceTrackers []*resources.Resource

	instancesToDelete := make(map[string]*resources.Resource)
	migsToDelete := make(map[string]*resources.Resource)
	for _, resource := range resourceMap {
		switch resource.Type {
		case typeInstance:
			instancesToDelete[resource.ID] = resource
		case typeInstanceGroupManager:
			migsToDelete[resource.ID] = resource

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Check IAM for compute.firewalls.delete on the project (or host project in shared VPC).
  2. If the rule is owned by GKE/another controller, delete it via that system or in the console rather than kops.
  3. Retry the delete; 429/5xx failures are typically transient.
  4. Confirm the rule is not recreated by an active controller; remove the source of recreation first.
  5. If already deleted, re-run — NotFound is treated as success.
Defensive patterns

Strategy: retry

Validate before calling

// confirm the firewall rule still exists and is kOps-owned before delete
fw, err := computeService.Firewalls.Get(project, ruleName).Do()
if err != nil { /* 404 means already gone */ }
if fw != nil && !strings.Contains(fw.Description, clusterTag) {
    return fmt.Errorf("firewall %s not owned by this cluster", ruleName)
}

Type guard

func isGCEAPIError(err error) (*googleapi.Error, bool) {
    var gerr *googleapi.Error
    return gerr, errors.As(err, &gerr)
}

Try / catch

err := deleteFirewallRule(t)
var gerr *googleapi.Error
if err != nil {
    if errors.As(err, &gerr) && gerr.Code == 404 { return nil } // fine
    if errors.As(err, &gerr) && (gerr.Code == 429 || gerr.Code >= 500) {
        // retry with backoff
    }
    return err
}

Prevention

When it happens

Trigger: c.Compute().Firewalls().Delete(u.Project, u.Name) returns 403 (missing compute.firewalls.delete), 429 quota, 5xx, or a conflict because the rule is managed/locked by another system (e.g. GKE control plane, shared VPC host project policies).

Common situations: Shared VPC setups where the kops service account lacks firewall permissions on the host project; firewall rules recreated by GKE or another controller racing the delete; expired/rotated credentials mid-teardown; transient GCP outages.

Related errors


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