{"record":{"id":"94657cb5b96c65b3","repo":"kubernetes/kops","slug":"error-deleting-subnetwork-s-v","errorCode":null,"errorMessage":"error deleting Subnetwork %s: %v","messagePattern":"error deleting Subnetwork (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/resources/gce/gce.go","lineNumber":952,"sourceCode":"}\n\nfunc deleteSubnet(cloud fi.Cloud, r *resources.Resource) error {\n\tc := cloud.(gce.GCECloud)\n\to := r.Obj.(*compute.Subnetwork)\n\n\tklog.V(2).Infof(\"deleting GCE Subnetwork %s\", o.SelfLink)\n\tu, err := gce.ParseGoogleCloudURL(o.SelfLink)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\top, err := c.Compute().Subnetworks().Delete(u.Project, u.Region, u.Name)\n\tif err != nil {\n\t\tif gce.IsNotFound(err) {\n\t\t\tklog.Infof(\"Subnetwork not found, assuming deleted: %q\", o.SelfLink)\n\t\t\treturn nil\n\t\t}\n\t\treturn fmt.Errorf(\"error deleting Subnetwork %s: %v\", o.SelfLink, err)\n\t}\n\n\treturn c.WaitForOp(op)\n}\n\nfunc (d *clusterDiscoveryGCE) listRouters() ([]*resources.Resource, error) {\n\tc := d.gceCloud\n\n\tvar resourceTrackers []*resources.Resource\n\tctx := context.Background()\n\n\trouters, err := c.Compute().Routers().List(ctx, c.Project(), c.Region())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error listing routers: %v\", err)\n\t}\n\n\tfor _, o := range routers {\n\t\tif !d.matchesClusterName(o.Name) {","sourceCodeStart":934,"sourceCodeEnd":970,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/resources/gce/gce.go#L934-L970","documentation":"Thrown by deleteSubnet in pkg/resources/gce/gce.go when the GCE Compute Subnetworks().Delete API returns an error other than NotFound (which is treated as already-deleted success). The message wraps the subnetwork self-link and the underlying Google API error. It signals cluster teardown failed to remove the subnetwork resource.","triggerScenarios":"Calling kops delete cluster on GCE where the subnetwork delete API call fails with a non-404 error: e.g. the subnetwork is still in use by resources (forwarding rules, instances with alias IPs), permission denied on the compute service account, quota/billing issues, or transient Google API 5xx errors.","commonSituations":"Cluster deletion fails partway leaving orphaned resources that still reference the subnet; IAM roles for the deletion service account lack compute.subnetworks.delete; regional subnet still used by a lingering instance group or load balancer; API outage/rate limiting during teardown.","solutions":["Inspect the wrapped %v error to find the root cause (403 permission, 400 failedPrecondition 'still in use', 429 rate limit, 5xx).","Delete dependent resources first (forwarding rules, target pools, instances using the subnet), then retry deletion.","Grant the service account compute.networkAdmin (or compute.subnetworks.delete permission) in the project.","Retry after backoff if the cause is a transient 429/5xx; kops delete cluster is idempotent (NotFound is tolerated)."],"exampleFix":"// before\nreturn fmt.Errorf(\"error deleting Subnetwork %s: %v\", o.SelfLink, err)\n// after (retry transient errors before failing)\nif gce.IsNotFound(err) {\n\treturn nil\n}\nif apiErr, ok := err.(*googleapi.Error); ok && (apiErr.Code == 429 || apiErr.Code >= 500) {\n\treturn fmt.Errorf(\"error deleting Subnetwork %s (transient, retry): %w\", o.SelfLink, err)\n}\nreturn fmt.Errorf(\"error deleting Subnetwork %s: %w\", o.SelfLink, err)","handlingStrategy":"retry","validationCode":"// before teardown, check subnet dependencies\nfor _, subnet := range []string{\"mysubnet\"} {\n\tinUse, _ := subnetHasForwardingRules(project, region, subnet)\n\tif inUse {\n\t\treturn fmt.Errorf(\"subnet %s still referenced; clean up first\", subnet)\n\t}\n}","typeGuard":"func isGoogleAPIError(err error) (*googleapi.Error, bool) {\n\tge, ok := err.(*googleapi.Error)\n\treturn ge, ok\n}","tryCatchPattern":"// treat NotFound as success, retry transient\ncall := func() error { return deleteSubnet(project, region, name) }\nif err := retry.OnError(wait.Backoff{Steps: 5, Duration: time.Second}, isTransient, call); err != nil {\n\tklog.Errorf(\"subnet delete failed permanently: %v\", err)\n}","preventionTips":["Ensure the deletion identity has compute.networkAdmin before running delete cluster.","Delete load balancers/instances before the subnet.","Re-run delete cluster after transient failures; it skips NotFound resources."],"tags":["gce","subnetwork","deletion","cloud-api"],"backgroundTag":"gce-resource-delete-failed","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}