{"record":{"id":"0de5ff279801104f","repo":"kubernetes/kops","slug":"failed-to-delete-network-s-s-w","errorCode":null,"errorMessage":"failed to delete network %s(%s): %w","messagePattern":"failed to delete network (.+?)\\((.+?)\\): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/resources/hetzner/resources.go","lineNumber":245,"sourceCode":"\tclient := c.SSHKeyClient()\n\tsshKey := r.Obj.(*hcloud.SSHKey)\n\t_, err := client.Delete(context.TODO(), sshKey)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to delete ssh key %s(%s): %w\", r.Name, r.ID, err)\n\t}\n\n\treturn nil\n}\n\nfunc deleteNetwork(cloud fi.Cloud, r *resources.Resource) error {\n\tklog.Infof(\"Deleting Network: %s(%s)\", r.Name, r.ID)\n\n\tc := cloud.(hetzner.HetznerCloud)\n\tclient := c.NetworkClient()\n\tnetwork := r.Obj.(*hcloud.Network)\n\t_, err := client.Delete(context.TODO(), network)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to delete network %s(%s): %w\", r.Name, r.ID, err)\n\t}\n\n\treturn nil\n}\n\nfunc deleteFirewall(cloud fi.Cloud, r *resources.Resource) error {\n\tklog.Infof(\"Deleting Firewall: %s(%s)\", r.Name, r.ID)\n\n\tc := cloud.(hetzner.HetznerCloud)\n\tclient := c.FirewallClient()\n\tfirewall := r.Obj.(*hcloud.Firewall)\n\t_, err := client.Delete(context.TODO(), firewall)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to delete firewall %s(%s): %w\", r.Name, r.ID, err)\n\t}\n\n\treturn nil\n}","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/resources/hetzner/resources.go#L227-L263","documentation":"Wrapped error returned by kOps' Hetzner deleteNetwork when the hcloud API client's NetworkClient.Delete call fails while tearing down the cluster network during `kops delete cluster`. The original hcloud error (auth, rate limit, conflict, network still in use) is preserved via %w so callers can errors.Is/As it.","triggerScenarios":"client.Delete(ctx, network) returns a non-nil error: invalid/expired hcloud token, network still attached to servers/load balancers (hcloud conflict), rate limiting (429), or network already deleted (hcloud not-found).","commonSituations":"Deleting a cluster whose servers or load balancers were removed out-of-band but still reference the network; stale KOPS_STATE_STORE credentials after token rotation; deleting the same cluster twice concurrently.","solutions":["Fix the underlying hcloud error: verify HCLOUD_TOKEN is valid and has write scope, and check the wrapped message for conflicts.","Detach all servers, load balancers and routes from the network in the Hetzner Cloud Console, then retry `kops delete cluster`.","If the resource no longer exists (not-found), rerun with `--yes` again or use `kops delete cluster` after refreshing state; kOps treats some not-found cases as done on the next pass.","Wait for hcloud rate-limit/reset windows if the wrapped error is 429, then retry."],"exampleFix":"// before: network in use by servers\nclient.Delete(context.TODO(), network) // fails: server(s) still attached\n// after: delete servers (deleteServer runs earlier) or detach interfaces first\n// ensure resource ordering: servers/volumes deleted before network\n// or manually: hcloud network remove-route / detach in console, then rerun","handlingStrategy":"retry","validationCode":"// preflight: check token and network usage before delete\nfunc canDeleteNetwork(ctx context.Context, c *hcloud.Client, id int) error {\n    net, _, err := c.Network.Get(ctx, strconv.Itoa(id))\n    if err != nil { return err }\n    if net == nil { return nil } // already gone\n    if len(net.Servers) > 0 || len(net.LoadBalancers) > 0 {\n        return fmt.Errorf(\"network %d still has %d servers / %d load balancers attached\", id, len(net.Servers), len(net.LoadBalancers))\n    }\n    return nil\n}","typeGuard":"func isHcloudNotFound(err error) bool {\n    var h_err hcloud.Error\n    return errors.As(err, &h_err) && h_err.Code == hcloud.ErrorCodeNotFound\n}","tryCatchPattern":"if err := deleteNetwork(...); err != nil {\n    var hErr hcloud.Error\n    if errors.As(err, &hErr) && hErr.Code == hcloud.ErrorCodeNotFound {\n        return nil // already deleted\n    }\n    if errors.As(err, &hErr) && hErr.Code == hcloud.ErrorCodeConflict {\n        return retryAfterDetaching(err)\n    }\n    return err\n}","preventionTips":["Always let kOps delete servers, volumes and load balancers before the network (its ordering does this; avoid out-of-band console deletions).","Rotate HCLOUD_TOKEN before starting a delete and confirm write scope.","Check `hcloud network describe` for attached resources prior to deletion.","Back off on 429s instead of hammering the API."],"tags":["hetzner","network","deletion","cloud-api"],"backgroundTag":"hcloud-api-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"}