argoproj/argo-workflows · error

Error applying PodSpecPatch

Error message

Error applying PodSpecPatch

What it means

After building the pod spec, the controller applies any podSpecPatch(es) with util.ApplyPodSpecPatch. If the resulting JSON/strategic-merge patch is invalid or cannot be applied to the generated pod spec, the build fails with this wrapped error.

Source

Thrown at workflow/controller/workflowpod.go:744

			}
		}
		return nil
	})
	if err != nil {
		return nil, err
	}

	// Apply the patch string from workflow and template
	var podSpecPatchs []string
	podSpecPatchs, err = pb.processPodSpecPatch(ctx, tmpl, pod)
	if err != nil {
		return nil, err
	}
	if len(podSpecPatchs) > 0 {
		var patchedPodSpec *apiv1.PodSpec
		patchedPodSpec, err = util.ApplyPodSpecPatch(pod.Spec, podSpecPatchs...)
		if err != nil {
			return nil, errors.Wrap(err, "", "Error applying PodSpecPatch")
		}
		pod.Spec = *patchedPodSpec
	}

	// In init-less mode the emissary binary is mounted at /argo-bin via the
	// argoexec-bin image volume, not copied to /var/run/argo by an init container.
	// K8s image volumes expose the image's root filesystem as-is.
	argoexecBinaryPath := pb.layout.argoexecBinaryPath()
	for i, c := range pod.Spec.Containers {
		if !common.IsArgoSidecar(c.Name) {
			// https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#notes
			if len(c.Command) == 0 {
				var x *entrypoint.Image
				x, err = pb.deps.lookupImage(ctx, c.Image, entrypoint.Options{
					Namespace: pb.in.namespace, ServiceAccountName: pb.in.execWfSpec.ServiceAccountName, ImagePullSecrets: pb.in.execWfSpec.ImagePullSecrets,
				})
				if err != nil {
					return nil, fmt.Errorf("failed to look-up entrypoint/cmd for image %q, you must either explicitly specify the command, or list the image's command in the index: https://argo-workflows.readthedocs.io/en/latest/workflow-executors/#emissary-emissary: %w", c.Image, err)

View on GitHub (pinned to 35bff19146)

Solutions

  1. Validate the patch JSON syntax and patch operations
  2. Ensure patched container names match generated containers ('main', 'init', 'wait')
  3. Print the generated pod (kubectl get pod -o yaml) and align the patch with its structure

Example fix

// before
podSpecPatch: '[{"op":"replace","path":"/containers/1/image","value":"foo"}]' // container 1 may not exist
// after
podSpecPatch: '[{"op":"replace","path":"/containers/0/image","value":"foo"}]'
Defensive patterns

Strategy: validation

Validate before calling

// validate patch JSON before applying
var check interface{}
if err := json.Unmarshal([]byte(patchStr), &check); err != nil {
  return fmt.Errorf("invalid podSpecPatch JSON: %w", err)
}

Try / catch

patched, err := util.ApplyPodSpecPatch(pod.Spec, patches...)
if err != nil {
  return nil, fmt.Errorf("error applying PodSpecPatch: %w", err)
}
pod.Spec = *patched

Prevention

When it happens

Trigger: podSpecPatch with invalid JSON, patching a container name that doesn't exist (e.g. not 'main'), or a patch incompatible with the generated pod spec structure.

Common situations: Hand-written JSON patches with wrong container names; strategic-merge patches that conflict with injected volumes/volumes mounts; multi-patch templates (with pod_spec_patch as output parameter) producing incompatible patches at runtime.

Related errors


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