istio/istio · error

pod %s/%s is unexpectedly not eligible for ambient enrollmen

Error message

pod %s/%s is unexpectedly not eligible for ambient enrollment

What it means

The pod WAS found and lookup succeeded, but GetPodIfAmbientEnabled returned nil because the enablement selector (ambient mesh label check against pod + namespace labels) did not match. The CNI plugin believed the pod was ambient-eligible; the agent disagreed.

Source

Thrown at cni/pkg/nodeagent/cni-watcher.go:233

	// The plugin already consulted the k8s API - but on this end handler caches may be stale, so retry a few times if we get no pod.
	// if err is returned, we couldn't find the pod
	// if nil is returned, we found it but ambient is not enabled
	for ambientPod, err = s.handlers.GetPodIfAmbientEnabled(name, namespace); (err != nil) && (retries < maxStaleRetries); retries++ {
		log.Warnf("got an event for pod %s in namespace %s not found in current pod cache, retry %d of %d",
			name, namespace, retries, maxStaleRetries)
		if !sleep.UntilContext(s.ctx, time.Duration(msInterval)*time.Millisecond) {
			return nil, fmt.Errorf("aborted")
		}
	}
	if err != nil {
		return nil, fmt.Errorf("failed to get pod %s/%s: %v", namespace, name, err)
	}

	// This shouldn't happen - the CNI plugin should only invoke us when a pod starts up that already meets
	// ambient eligibility requirements.
	if ambientPod == nil {
		return nil, fmt.Errorf("pod %s/%s is unexpectedly not eligible for ambient enrollment", namespace, name)
	}
	return ambientPod, nil
}

View on GitHub (pinned to 8dc789c5cf)

Solutions

  1. Verify labels: `kubectl get pod <pod> -o jsonpath='{.metadata.labels}'` and same for the namespace; check istio.io/dataplane-mode
  2. Ensure mutating webhooks that apply the ambient label run BEFORE CNI ADD (correct webhook priority/failurePolicy)
  3. Recreate or annotate the pod so the CNI plugin re-evaluates eligibility
  4. Confirm istio-cni plugin and agent versions match (no eligibility-criteria skew)
Defensive patterns

Strategy: validation

Validate before calling

// before invoking enrollment, confirm eligibility the same way the agent does
ns, pod := nsCache.Get(nsName), podCache.Get(podName, nsName)
if pod == nil || ns == nil || !enablementSelector.Matches(pod, ns.Labels) {
    return errors.New("pod not ambient-eligible; check istio.io/dataplane-mode labels")
}

Type guard

func isAmbientEligible(pod *corev1.Pod, ns *corev1.Namespace, sel EnablementSelector) bool {
    if pod == nil || ns == nil {
        return false
    }
    return sel.Matches(pod, ns.Labels)
}

Prevention

When it happens

Trigger: Pod or namespace lacks the ambient enrollment label (istio.io/dataplane-mode=ambient) at handler time, or it was removed; label present on pod but namespace label mismatch (or vice versa) depending on selector semantics; stale plugin-side decision.

Common situations: Namespace opt-in vs pod opt-out label combinations; the label added by a mutating webhook that had not run when the CNI plugin checked; label removed while the pod was starting; version skew between plugin and agent on what counts as eligible.

Related errors


AI-assisted analysis of istio/istio@8dc789c5cf (2026-08-15). Data as JSON: /api/errors/781d9f55e8a93258. Report an issue: GitHub.