argoproj/argo-workflows · error

containers must have at least one container

Error message

containers must have at least one container

What it means

ContainerSetTemplate.Validate enforces that a container set declares at least one container. This structural validation guard fires during workflow/template validation (via validateContainerSetTemplate and validateLeaf) when a template uses a containerSet with an empty containers list, which cannot produce a runnable pod.

Source

Thrown at pkg/apis/workflow/v1alpha1/container_set_template_types.go:92

	if in == nil {
		return nil
	}
	return in.Containers
}

func (in *ContainerSetTemplate) HasSequencedContainers() bool {
	for _, n := range in.GetGraph() {
		if len(n.Dependencies) > 0 {
			return true
		}
	}
	return false
}

// Validate checks if the ContainerSetTemplate is valid
func (in *ContainerSetTemplate) Validate() error {
	if len(in.Containers) == 0 {
		return fmt.Errorf("containers must have at least one container")
	}

	names := make([]string, 0)
	for _, ctr := range in.Containers {
		names = append(names, ctr.Name)
	}
	err := validateWorkflowFieldNames(names, false)
	if err != nil {
		return fmt.Errorf("containers%s", err.Error())
	}

	// Ensure there are no collisions with volume mountPaths and artifact load paths
	mountPaths := make(map[string]string)
	for i, volMount := range in.VolumeMounts {
		if prev, ok := mountPaths[volMount.MountPath]; ok {
			return fmt.Errorf("volumeMounts[%d].mountPath '%s' already mounted in %s", i, volMount.MountPath, prev)
		}
		mountPaths[volMount.MountPath] = fmt.Sprintf("volumeMounts.%s", volMount.Name)

View on GitHub (pinned to 35bff19146)

Solutions

  1. Add at least one container entry with a valid name and image under containerSet.containers.
  2. Fix the templating/variable that caused the containers list to render empty.
  3. If you only need a single container, use a plain container/script template instead of a containerSet.

Example fix

// before
containerSet:
  containers: []
// after
containerSet:
  containers:
    - name: main
      image: alpine:3.18
Defensive patterns

Strategy: validation

Validate before calling

if cs.ContainerSet != nil && len(cs.ContainerSet.Containers) == 0 {
    return fmt.Errorf("containerSet requires at least one container")
}

Try / catch

if err := cs.Validate(); err != nil {
    if strings.Contains(err.Error(), "must have at least one container") {
        // fall back to a regular container template or reject the manifest
    }
    return err
}

Prevention

When it happens

Trigger: Submitting or validating a workflow whose containerSet.containers array is empty or omitted, e.g. containers: [] in the template spec.

Common situations: Templating engine rendered the containers list away (empty loop/conditional); user wrote a containerSet but left the containers block blank; YAML key misspelled so containers is nil.

Related errors


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