kubernetes/kops · error

load balancer %s(%d) is not public

Error message

load balancer %s(%d) is not public

What it means

GetApiIngressStatus requires the API load balancer to have a public network interface so it can return a public ingress IP. If lb.PublicNet.Enabled is false, it refuses with this error because a private-only LB cannot serve the Kubernetes API endpoint.

Source

Thrown at upup/pkg/fi/cloudup/hetzner/cloud.go:448

// FindClusterStatus was used before etcd-manager to check the etcd cluster status and prevent unsupported changes.
func (c *hetznerCloudImplementation) FindClusterStatus(cluster *kops.Cluster) (*kops.ClusterStatus, error) {
	return nil, nil
}

func (c *hetznerCloudImplementation) GetApiIngressStatus(cluster *kops.Cluster) ([]fi.ApiIngressStatus, error) {
	lbName := "api." + cluster.Name

	client := c.LoadBalancerClient()
	lb, _, err := client.GetByName(context.TODO(), lbName)
	if err != nil {
		return nil, fmt.Errorf("failed to get info for load balancer %q: %w", lbName, err)
	}
	if lb == nil {
		return nil, nil
	}

	if !lb.PublicNet.Enabled {
		return nil, fmt.Errorf("load balancer %s(%d) is not public", lb.Name, lb.ID)
	}

	ingresses := []fi.ApiIngressStatus{
		{
			IP: lb.PublicNet.IPv4.IP.String(),
		},
	}

	return ingresses, nil
}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Enable the public network on the load balancer in the Hetzner Cloud console (or via API).
  2. Run `kops update cluster --yes` to let kOps recreate the LB per spec.
  3. Verify the cluster spec's API load balancer configuration matches a public LB (`kops edit cluster`).
  4. If a fully private control plane is intended, this code path does not support it; use a different API access mechanism.
Defensive patterns

Strategy: validation

Validate before calling

lbs, _, _ := client.LoadBalancer.List(ctx, hcloud.LoadBalancerListOpts{Name: lbName})
for _, lb := range lbs {
  if !lb.PublicNet.Enabled { return fmt.Errorf("LB %s must have public net enabled", lb.Name) }
}

Type guard

func lbIsPublic(lb *hcloud.LoadBalancer) bool { return lb != nil && lb.PublicNet.Enabled }

Prevention

When it happens

Trigger: The Hetzner load balancer named "api.<cluster>" exists but was created/modified with PublicNet disabled (e.g. private-only setup or manual LB edit).

Common situations: Someone toggled the LB to private-only in the Hetzner console; a cluster spec change removed the public IP expectation but the kOps code still requires it; importing an existing manually created private LB.

Related errors


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