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
- Verify labels: `kubectl get pod <pod> -o jsonpath='{.metadata.labels}'` and same for the namespace; check istio.io/dataplane-mode
- Ensure mutating webhooks that apply the ambient label run BEFORE CNI ADD (correct webhook priority/failurePolicy)
- Recreate or annotate the pod so the CNI plugin re-evaluates eligibility
- 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
- Keep plugin and agent eligibility logic in one shared function to avoid skew
- Order mutating webhooks so ambient labels exist before CNI ADD
- Monitor this error to catch label drift in ambient namespaces
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
- failed to get pod %s/%s: %v
- failed to find namespace %v
- failed to find pod %v
- unexpected event type: %+v
- can't find netns for pod, this is ok if this is a newly crea
AI-assisted analysis of istio/istio@8dc789c5cf (2026-08-15).
Data as JSON: /api/errors/781d9f55e8a93258.
Report an issue: GitHub.