tailscale/tailscale · error

failed to check if any Pods are configured: %w

Error message

failed to check if any Pods are configured: %w

What it means

Thrown by HAIngressReconciler.maybeProvision when numberPodsAdvertising fails: it lists the ProxyGroup's state Secrets (label-selected on ProxyGroup name and secret type state) and parses device prefs from each. The wrapped error is either the Secret list call failing (RBAC/apiserver) or getDevicePrefs choking on a state Secret whose prefs bytes do not unmarshal ('error getting node metadata'). The count is used to decide whether Ingress status may advertise the service.

Source

Thrown at cmd/k8s-operator/ingress-for-pg.go:380

		if err := tsClient.VIPServices().CreateOrUpdate(ctx, tsSvc); err != nil {
			return false, fmt.Errorf("error creating Tailscale Service: %w", err)
		}
	}

	// 5. Update tailscaled's AdvertiseServices config, which should add the Tailscale Service
	// IPs to the ProxyGroup Pods' AllowedIPs in the next netmap update if approved.
	mode := serviceAdvertisementHTTPS
	if isHTTPEndpointEnabled(ing) || isHTTPRedirectEnabled(ing) {
		mode = serviceAdvertisementHTTPAndHTTPS
	}
	if err = r.maybeUpdateAdvertiseServicesConfig(ctx, serviceName, mode, pg); err != nil {
		return false, fmt.Errorf("failed to update tailscaled config: %w", err)
	}

	// 6. Update Ingress status if ProxyGroup Pods are ready.
	count, err := numberPodsAdvertising(ctx, r.Client, r.tsNamespace, pg.Name, serviceName.String())
	if err != nil {
		return false, fmt.Errorf("failed to check if any Pods are configured: %w", err)
	}

	oldStatus := ing.Status.DeepCopy()

	switch count {
	case 0:
		ing.Status.LoadBalancer.Ingress = nil
	default:
		var ports []networkingv1.IngressPortStatus
		hasCerts, err := hasCerts(ctx, r.Client, r.tsNamespace, serviceName, pg)
		if err != nil {
			return false, fmt.Errorf("error checking TLS credentials provisioned for Ingress: %w", err)
		}
		// If TLS certs have not been issued (yet), do not set port 443.
		if hasCerts {
			ports = append(ports, networkingv1.IngressPortStatus{
				Protocol: "TCP",
				Port:     443,

View on GitHub (pinned to cfe32b8be6)

Solutions

  1. Read the wrapped error: 'error getting node metadata' means a corrupt state Secret; inspect the ProxyGroup's state Secrets (kubectl get secrets -n <operator-ns> -l tailscale.com/parent=<pg>) and delete the corrupt/orphaned one so the pod regenerates it.
  2. 'forbidden'/apiserver errors: reapply RBAC or wait out the transient; the reconcile backoff retries.
  3. Ensure ProxyGroup Pods are healthy so they rewrite valid state Secrets.
Defensive patterns

Strategy: retry

Type guard

func isCorruptStateSecretErr(err error) bool {
	return err != nil && strings.Contains(err.Error(), "node metadata")
}

Try / catch

count, err := numberPodsAdvertising(ctx, r.Client, r.tsNamespace, pg.Name, serviceName.String())
if err != nil {
	if isCorruptStateSecretErr(err) {
		logger.Error("corrupt ProxyGroup state Secret; regenerate it before retrying")
	}
	return ctrl.Result{}, fmt.Errorf("failed to check if any Pods are configured: %w", err)
}

Prevention

When it happens

Trigger: List of state Secrets in the operator namespace denied or failing; a state Secret written partially, hand-edited, or left by a different operator version so prefs do not unmarshal; ctx cancelled while listing.

Common situations: ProxyGroup replica scaled up/down leaving stale Secrets; state Secret corrupted after a pod crash mid-write; restrictive admission/OPA blocking list; apiserver throttling.

Related errors


AI-assisted analysis of tailscale/tailscale@cfe32b8be6 (2026-08-15). Data as JSON: /api/errors/51d0227e84c90b7e. Report an issue: GitHub.