kubernetes/kops · error

failed to delete load balancer %s(%s): %w

Error message

failed to delete load balancer %s(%s): %w

What it means

Wrapped error from deleteLoadBalancer: hcloud LoadBalancerClient.Delete returned an error while kOps removes the cluster's Hetzner load balancer. The API error (auth, conflict, rate limit, not-found) is preserved through %w.

Source

Thrown at pkg/resources/hetzner/resources.go:273

	client := c.FirewallClient()
	firewall := r.Obj.(*hcloud.Firewall)
	_, err := client.Delete(context.TODO(), firewall)
	if err != nil {
		return fmt.Errorf("failed to delete firewall %s(%s): %w", r.Name, r.ID, err)
	}

	return nil
}

func deleteLoadBalancer(cloud fi.Cloud, r *resources.Resource) error {
	klog.Infof("Deleting LoadBalancer: %s(%s)", r.Name, r.ID)

	c := cloud.(hetzner.HetznerCloud)
	client := c.LoadBalancerClient()
	loadBalancer := r.Obj.(*hcloud.LoadBalancer)
	_, err := client.Delete(context.TODO(), loadBalancer)
	if err != nil {
		return fmt.Errorf("failed to delete load balancer %s(%s): %w", r.Name, r.ID, err)
	}

	return nil
}

func deleteServer(cloud fi.Cloud, r *resources.Resource) error {
	ctx := context.TODO()

	klog.Infof("Deleting Server: %s(%s)", r.Name, r.ID)

	c := cloud.(hetzner.HetznerCloud)
	serverClient := c.ServerClient()
	actionClient := c.ActionClient()

	server := r.Obj.(*hcloud.Server)
	result, _, err := serverClient.DeleteWithResult(ctx, server)
	if err != nil {
		return fmt.Errorf("failed to delete server %s(%s): %w", r.Name, r.ID, err)

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Delete or detach all load balancer targets in the Hetzner console, then retry the delete.
  2. Check token validity and permissions (HCLOUD_TOKEN).
  3. If not-found, the LB is already removed — rerun delete to refresh state.
  4. Back off and retry if the wrapped error indicates rate limiting.
Defensive patterns

Strategy: retry

Validate before calling

lb, _, err := c.LoadBalancer.Get(ctx, name)
if err != nil { return err }
if lb != nil && len(lb.Targets) > 0 {
    return fmt.Errorf("load balancer %s still has %d targets", name, len(lb.Targets))
}

Type guard

func isRateLimited(err error) bool {
    var hErr hcloud.Error
    return errors.As(err, &hErr) && hErr.Code == hcloud.ErrorCodeRateLimitExceeded
}

Try / catch

for attempt := 0; attempt < 3; attempt++ {
    err := deleteLoadBalancer(...)
    if err == nil { return nil }
    var hErr hcloud.Error
    if errors.As(err, &hErr) && (hErr.Code == hcloud.ErrorCodeNotFound || hErr.Code == hcloud.ErrorCodeRateLimitExceeded) {
        time.Sleep(time.Duration(1<<attempt) * time.Second)
        continue
    }
    return err
}
return err

Prevention

When it happens

Trigger: client.Delete(ctx, loadBalancer) fails: load balancer still has targets/services attached, invalid token, rate limiting, or already deleted externally.

Common situations: Servers were deleted out-of-band leaving stale LB targets; LB managed by both kOps and a Kubernetes service controller; expired credentials during long-lived cluster teardown.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/ffb3431fad18a63d. Report an issue: GitHub.