{"record":{"id":"291f85fd8a0c07fd","repo":"kubernetes/kops","slug":"error-deleting-firewallrule-s-v","errorCode":null,"errorMessage":"error deleting FirewallRule %s: %v","messagePattern":"error deleting FirewallRule (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/resources/gce/gce.go","lineNumber":723,"sourceCode":"\n// deleteFirewallRule is the helper function to delete a Resource for a Firewall object\nfunc deleteFirewallRule(cloud fi.Cloud, r *resources.Resource) error {\n\tc := cloud.(gce.GCECloud)\n\tt := r.Obj.(*compute.Firewall)\n\n\tklog.V(2).Infof(\"Deleting GCE FirewallRule %s\", t.SelfLink)\n\tu, err := gce.ParseGoogleCloudURL(t.SelfLink)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\top, err := c.Compute().Firewalls().Delete(u.Project, u.Name)\n\tif err != nil {\n\t\tif gce.IsNotFound(err) {\n\t\t\tklog.Infof(\"FirewallRule not found, assuming deleted: %q\", t.SelfLink)\n\t\t\treturn nil\n\t\t}\n\t\treturn fmt.Errorf(\"error deleting FirewallRule %s: %v\", t.SelfLink, err)\n\t}\n\n\treturn c.WaitForOp(op)\n}\n\nfunc (d *clusterDiscoveryGCE) listRoutes(ctx context.Context, resourceMap map[string]*resources.Resource) ([]*resources.Resource, error) {\n\tc := d.gceCloud\n\n\tvar resourceTrackers []*resources.Resource\n\n\tinstancesToDelete := make(map[string]*resources.Resource)\n\tmigsToDelete := make(map[string]*resources.Resource)\n\tfor _, resource := range resourceMap {\n\t\tswitch resource.Type {\n\t\tcase typeInstance:\n\t\t\tinstancesToDelete[resource.ID] = resource\n\t\tcase typeInstanceGroupManager:\n\t\t\tmigsToDelete[resource.ID] = resource","sourceCodeStart":705,"sourceCodeEnd":741,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/resources/gce/gce.go#L705-L741","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Check IAM for compute.firewalls.delete on the project (or host project in shared VPC).","If the rule is owned by GKE/another controller, delete it via that system or in the console rather than kops.","Retry the delete; 429/5xx failures are typically transient.","Confirm the rule is not recreated by an active controller; remove the source of recreation first.","If already deleted, re-run — NotFound is treated as success."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// confirm the firewall rule still exists and is kOps-owned before delete\nfw, err := computeService.Firewalls.Get(project, ruleName).Do()\nif err != nil { /* 404 means already gone */ }\nif fw != nil && !strings.Contains(fw.Description, clusterTag) {\n    return fmt.Errorf(\"firewall %s not owned by this cluster\", ruleName)\n}","typeGuard":"func isGCEAPIError(err error) (*googleapi.Error, bool) {\n    var gerr *googleapi.Error\n    return gerr, errors.As(err, &gerr)\n}","tryCatchPattern":"err := deleteFirewallRule(t)\nvar gerr *googleapi.Error\nif err != nil {\n    if errors.As(err, &gerr) && gerr.Code == 404 { return nil } // fine\n    if errors.As(err, &gerr) && (gerr.Code == 429 || gerr.Code >= 500) {\n        // retry with backoff\n    }\n    return err\n}","preventionTips":["Grant compute.firewalls.delete on the project (and host project for shared VPC)","Disable GKE/controllers that recreate firewall rules before kops teardown","Serialize cluster deletion — no concurrent kops runs on the same cluster","Retry 429/5xx with exponential backoff","Remember NotFound is treated as success; just re-run after transient failures"],"tags":["gce","gcp","firewall","delete","teardown"],"backgroundTag":"gcp-resource-delete-conflict","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}