kubernetes/kops · error

did not find API endpoint

Error message

did not find API endpoint

What it means

After querying GetApiIngressStatus, findSystemEndpoints builds a list of SystemEndpoint values (kops-controller and kube-apiserver addresses). If the cloud returns an empty ingress list — no hostnames and no IPs — there is nothing to publish and the controller raises 'did not find API endpoint'. This prevents creating a KopsControlPlane whose status has no usable endpoints, which would later break bootstrap-data generation.

Source

Thrown at pkg/controllers/clusterapi/cluster_controller.go:228

			target.Endpoint = ingress.Hostname
		}
		if ingress.IP != "" {
			target.Endpoint = ingress.IP
		}
		target.Type = capikops.SystemEndpointTypeKubeAPIServer
		if ingress.InternalEndpoint {
			target.Scope = capikops.SystemEndpointScopeInternal
		} else {
			target.Scope = capikops.SystemEndpointScopeExternal
		}
		targets = append(targets, target)
	}

	// TODO: Sort targets
	// TODO: Mark targets as atomic list

	if len(targets) == 0 {
		return nil, fmt.Errorf("did not find API endpoint")
	}

	return targets, nil
}

func (s *clusterScope) createKopsControlPlane(ctx context.Context, kube client.Client) error {
	// This is because of network tags in cloud-provider-gcp
	// TODO: cloud-provider-gcp should not assume cluster name is a valid prefix
	name := gce.SafeClusterName(s.Cluster.GetName())

	status := capikops.KopsControlPlaneStatus{}

	systemEndpoints, err := s.findSystemEndpoints(ctx)
	if err != nil {
		return err
	}
	status.SystemEndpoints = systemEndpoints

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Wait for the API load balancer to be assigned an IP/hostname and re-reconcile (controller will retry)
  2. Verify the load balancer frontend and target pools/backends are configured in the cloud console
  3. Check the cluster spec networking (subnets, networkID) matches the actual cloud resources
  4. If using internal-only endpoints, confirm the provider surfaces internal ingress entries

Example fix

// before
if len(targets) == 0 {
    return nil, fmt.Errorf("did not find API endpoint")
}
// after: requeue instead of erroring while the LB is still provisioning
if len(targets) == 0 {
    return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
}
Defensive patterns

Strategy: retry

Validate before calling

ingresses, _ := cloud.GetApiIngressStatus(clusterInternal)
if len(ingresses) == 0 {
    klog.Warning("API load balancer has no ingress addresses yet")
}

Try / catch

endpoints, err := s.findSystemEndpoints(ctx)
if err != nil && err.Error() == "did not find API endpoint" {
    return ctrl.Result{RequeueAfter: 30 * time.Second}, nil // LB still provisioning
}

Prevention

When it happens

Trigger: The API load balancer has no ingress entries yet (LB created but no addresses assigned), the load balancer was deleted, or the cloud provider returns an empty list for a cluster whose networking is not yet wired (e.g. missing subnets/frontend IP).

Common situations: Reconcile fires immediately after cluster creation before the LB gets an external IP/hostname; private-only clusters where only internal endpoints exist and the provider omits them; LB misconfiguration in the cloud console.

Related errors


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