{"record":{"id":"de0456663089ac6c","repo":"kubernetes/kops","slug":"failed-to-delete-firewall-s-s-w","errorCode":null,"errorMessage":"failed to delete firewall %s(%s): %w","messagePattern":"failed to delete firewall (.+?)\\((.+?)\\): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/resources/hetzner/resources.go","lineNumber":259,"sourceCode":"\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}\n\nfunc deleteLoadBalancer(cloud fi.Cloud, r *resources.Resource) error {\n\tklog.Infof(\"Deleting LoadBalancer: %s(%s)\", r.Name, r.ID)\n\n\tc := cloud.(hetzner.HetznerCloud)\n\tclient := c.LoadBalancerClient()\n\tloadBalancer := r.Obj.(*hcloud.LoadBalancer)\n\t_, err := client.Delete(context.TODO(), loadBalancer)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to delete load balancer %s(%s): %w\", r.Name, r.ID, err)\n\t}\n\n\treturn nil\n}","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/resources/hetzner/resources.go#L241-L277","documentation":"Wrapped error from deleteFirewall in kOps' Hetzner resource cleanup, raised when hcloud FirewallClient.Delete fails while removing the cluster firewall during cluster teardown. The hcloud API error is wrapped with %w.","triggerScenarios":"client.Delete(ctx, firewall) fails: invalid token, firewall applied to servers still active (conflict), rate limit, or firewall already gone (not-found).","commonSituations":"Token rotated or expired between create and delete; manual edits in Hetzner console left the firewall applied to servers; concurrent kOps delete runs racing on the same firewall.","solutions":["Verify the Hetzner API token is valid with write permissions.","Remove the firewall from all servers in the Hetzner console (or let kOps delete the servers first), then retry.","If error is not-found, the firewall is already gone — rerun delete; kOps will refresh state.","Retry after rate-limit window if the wrapped error is a 429."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"fw, _, err := c.Firewall.Get(ctx, name)\nif err != nil { return err }\nif fw != nil && len(fw.AppliedTo) > 0 {\n    return fmt.Errorf(\"firewall %s still applied to %d resources\", name, len(fw.AppliedTo))\n}","typeGuard":"func isHcloudConflict(err error) bool {\n    var hErr hcloud.Error\n    return errors.As(err, &hErr) && hErr.Code == hcloud.ErrorCodeConflict\n}","tryCatchPattern":"err := deleteFirewall(...)\nvar hErr hcloud.Error\nif errors.As(err, &hErr) {\n    switch hErr.Code {\n    case hcloud.ErrorCodeNotFound:\n        return nil\n    case hcloud.ErrorCodeConflict:\n        return detachFirewallThenRetry(err)\n    }\n}\nreturn err","preventionTips":["Avoid manually attaching the kOps-managed cluster firewall to servers in the Hetzner console.","Keep the API token valid for the entire delete operation.","Use `hcloud firewall describe` to confirm no applied-to targets before deleting.","Do not run two `kops delete cluster` invocations concurrently."],"tags":["hetzner","firewall","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"}