argoproj/argo-workflows · error

-1

-1

Error message

Could not find wait container in pod spec

What it means

GetWaitContainerIndex scans pod.Spec.Containers for the Argo 'wait' container and returns -1 with this error when none is found. Every legacy workflow pod must include the wait sidecar, which performs artifact/output capture; its absence means the pod is not a valid Argo workflow pod for the legacy layout.

Source

Thrown at workflow/util/util.go:1749

		return false
	}

	if platform, keyExists := nodeSelector["kubernetes.io/os"]; keyExists && platform == "windows" {
		return true
	}

	return false
}

func FindWaitCtrIndex(pod *apiv1.Pod) (int, error) {
	waitCtrIndex := -1
	for i, ctr := range pod.Spec.Containers {
		if ctr.Name == common.WaitContainerName {
			waitCtrIndex = i
		}
	}
	if waitCtrIndex == -1 {
		err := errors.Errorf("-1", "Could not find wait container in pod spec")
		return -1, err
	}
	return waitCtrIndex, nil
}

// FindAuxiliaryCtrIndex returns the index of the auxiliary executor container
// on the pod — wait in the legacy layout, supervisor in the init-less layout.
// Returns -1 and an error if neither is found.
func FindAuxiliaryCtrIndex(pod *apiv1.Pod) (int, error) {
	for i, ctr := range pod.Spec.Containers {
		if ctr.Name == common.WaitContainerName || ctr.Name == common.SupervisorContainerName {
			return i, nil
		}
	}
	return -1, errors.Errorf("-1", "Could not find wait or supervisor container in pod spec")
}

View on GitHub (pinned to 35bff19146)

Solutions

  1. If running the init-less/emissary runtime, use FindAuxiliaryCtrIndex instead, which matches both wait and supervisor containers
  2. Verify the workflow pod template still includes common.WaitContainerName in spec.containers
  3. Check whether an admission webhook or security policy is removing containers from workflow pods
  4. Ensure you are not inspecting a non-workflow pod (plain k8s pod without Argo executor setup)

Example fix

// before
idx, err := util.GetWaitContainerIndex(pod)
// after (works for both legacy and init-less pods)
idx, err := util.FindAuxiliaryCtrIndex(pod)
Defensive patterns

Strategy: validation

Validate before calling

func hasWaitContainer(pod *apiv1.Pod) bool {
    for _, c := range pod.Spec.Containers {
        if c.Name == common.WaitContainerName {
            return true
        }
    }
    return false
}

Type guard

func isLegacyWorkflowPod(pod *apiv1.Pod) bool {
    _, found := pod.Labels[common.LabelKeyWorkflow]
    return found && hasWaitContainer(pod)
}

Try / catch

idx, err := util.GetWaitContainerIndex(pod)
if err != nil {
    // fall back to init-less layout
    if idx2, err2 := util.FindAuxiliaryCtrIndex(pod); err2 == nil {
        idx = idx2
    } else {
        return fmt.Errorf("no executor container in pod %s: %w", pod.Name, err)
    }
}

Prevention

When it happens

Trigger: Calling GetWaitContainerIndex on a pod built without the wait container: init-less (emissary/supervisor) pods that lack the legacy wait sidecar, hand-edited pod specs, pods whose wait container was removed by a mutating webhook or admission policy.

Common situations: Running with the init-less/supervisor container runtime (SOCKS5/emissary mode) while code still expects the legacy wait container; cluster policies (e.g. Istio sidecar injection policies or security controllers) stripping containers; users manually editing generated pod manifests.

Related errors


AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03). Data as JSON: /api/errors/3e584155eaccb9fa. Report an issue: GitHub.