{"record":{"id":"a197b57850d07398","repo":"kubernetes/kops","slug":"error-deleting-route-s-v","errorCode":null,"errorMessage":"error deleting Route %s: %v","messagePattern":"error deleting Route (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/resources/gce/gce.go","lineNumber":821,"sourceCode":"}\n\nfunc deleteRoute(cloud fi.Cloud, r *resources.Resource) error {\n\tc := cloud.(gce.GCECloud)\n\tt := r.Obj.(*compute.Route)\n\n\tklog.V(2).Infof(\"Deleting GCE Route %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().Routes().Delete(u.Project, u.Name)\n\tif err != nil {\n\t\tif gce.IsNotFound(err) {\n\t\t\tklog.Infof(\"Route not found, assuming deleted: %q\", t.SelfLink)\n\t\t\treturn nil\n\t\t}\n\t\treturn fmt.Errorf(\"error deleting Route %s: %v\", t.SelfLink, err)\n\t}\n\n\treturn c.WaitForOp(op)\n}\n\nfunc (d *clusterDiscoveryGCE) listAddresses() ([]*resources.Resource, error) {\n\tc := d.gceCloud\n\n\tvar resourceTrackers []*resources.Resource\n\n\tctx := context.Background()\n\n\taddrs, err := c.Compute().Addresses().List(ctx, c.Project(), c.Region())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error listing Addresses: %v\", err)\n\t}\n\n\tfor _, a := range addrs {","sourceCodeStart":803,"sourceCodeEnd":839,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/resources/gce/gce.go#L803-L839","documentation":"Wraps a failure from Compute Routes().Delete in deleteRoute during cluster teardown. NotFound is treated as already-deleted success; other failures — most notably 412 conflict when the route is still assigned to an instance (kOps routes are per-instance and held by VM network interfaces) — surface here with the route SelfLink and raw error.","triggerScenarios":"c.Compute().Routes().Delete(u.Project, u.Name) returns 412 'route is being used by an instance', 403 permission denied, 429 rate limit, or 5xx. The 412 in-use case is characteristic: kOps routes stay in use while the instance still exists.","commonSituations":"Deleting a cluster while instances are still running (route held by the VM's NIC); instance group manager deletion failed earlier leaving VMs behind; shared VPC permission gaps; concurrent teardown runs.","solutions":["Ensure instances/instance groups are deleted before routes — re-run teardown so VMs are removed first, freeing the routes.","Wait for the holding VM to be deleted, then retry kops delete cluster (deletes are resumable).","Check compute.routes.delete IAM permission, especially on shared VPC host projects.","If the VM is already gone in the console but GCP still holds the route, wait a few minutes for propagation and retry.","Force-delete orphaned VMs in the console, then re-run."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// check whether any instance still uses this route (412 prevention)\nroute, err := computeService.Routes.Get(project, routeName).Do()\nif err == nil && route.NextHopInstance != \"\" {\n    inst := lastComponent(route.NextHopInstance)\n    if _, err := computeService.Instances.Get(project, zone, inst).Do(); err == nil {\n        return fmt.Errorf(\"instance %s still holds route %s; delete instances first\", inst, routeName)\n    }\n}","typeGuard":"func isGCEAPIError(err error) (*googleapi.Error, bool) {\n    var gerr *googleapi.Error\n    return gerr, errors.As(err, &gerr)\n}","tryCatchPattern":"err := deleteRoute(t)\nvar gerr *googleapi.Error\nif err != nil {\n    if errors.As(err, &gerr) && gerr.Code == 404 { return nil }\n    if errors.As(err, &gerr) && (gerr.Code == 412 || gerr.Code == 429 || gerr.Code >= 500) {\n        // wait for VMs to drain / backoff, then retry\n    }\n    return err\n}","preventionTips":["Delete instances/instance group managers before routes — kOps teardown ordering handles this if uninterupted","Re-run kops delete cluster after partial failures; teardown is resumable and 404 = success","Verify compute.routes.delete IAM, especially on shared VPC host projects","Confirm VMs are actually gone in the console before assuming a 412 is permanent","Avoid concurrent teardown runs racing on the same routes"],"tags":["gce","gcp","routes","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-12T07:17:12.445Z"}