argoproj/argo-workflows · error

Error occurred during strategic merge patch

Error message

Error occurred during strategic merge patch

What it means

After converting the patch to JSON, ApplyPodSpecPatch applies it to the base PodSpec using sigs.k8s.io/structured-merge-diff's strategicpatch.StrategicMergePatch with apiv1.PodSpec as the schema. If the merge itself fails — typically because the patch JSON, while valid, is structurally incompatible with PodSpec's merge strategy (e.g. wrong types for patch-merge keys, non-object where an object is required) — the error is wrapped as "Error occurred during strategic merge patch".

Source

Thrown at workflow/util/util.go:1699

	if err != nil {
		return nil, errors.Wrap(err, "", "Failed to marshal the Pod spec")
	}

	for _, podSpecPatchYaml := range podSpecPatchYamls {
		// must convert to json because PodSpec has only json tags
		podSpecPatchJSON, convertErr := ConvertYAMLToJSON(podSpecPatchYaml)
		if convertErr != nil {
			return nil, errors.Wrap(convertErr, "", "Failed to convert the PodSpecPatch yaml to json")
		}

		// validate the patch to be a PodSpec
		if unmarshalErr := json.Unmarshal([]byte(podSpecPatchJSON), &apiv1.PodSpec{}); unmarshalErr != nil {
			return nil, fmt.Errorf("invalid podSpecPatch %q: %w", podSpecPatchYaml, unmarshalErr)
		}

		podSpecJSON, err = strategicpatch.StrategicMergePatch(podSpecJSON, []byte(podSpecPatchJSON), apiv1.PodSpec{})
		if err != nil {
			return nil, errors.Wrap(err, "", "Error occurred during strategic merge patch")
		}
	}

	var newPodSpec apiv1.PodSpec
	err = json.Unmarshal(podSpecJSON, &newPodSpec)
	if err != nil {
		return nil, errors.Wrap(err, "", "Error in Unmarshalling after merge the patch")
	}
	return &newPodSpec, nil
}

func GetNodeType(tmpl *wfv1.Template) wfv1.NodeType {
	return tmpl.GetNodeType()
}

// IsWindowsUNCPath checks if path is prefixed with \\
// This can be used to skip any processing of paths
// that point to SMB shares, local named pipes and local UNC path

View on GitHub (pinned to 35bff19146)

Solutions

  1. Validate the patch against the PodSpec schema: run `kubectl patch --dry-run=server pod ... -p <patch>` or use kubectl's client-side validation to see the precise merge failure.
  2. Fix the patch shape: containers/volumes must be arrays; align types with the Kubernetes API (booleans as booleans, ints as ints).
  3. Note the code separately rejects patches that don't unmarshal into PodSpec with a clearer message — if you see this wrap instead, the JSON parsed but the merge strategy failed; simplify the patch and add fields back one at a time.

Example fix

# before
podSpecPatch: |
  containers:            # object instead of list -> merge error
    name: main
    image: my-image
# after
podSpecPatch: |
  containers:
    - name: main         # list of objects, merged by name (patchMergeKey)
      image: my-image
Defensive patterns

Strategy: validation

Validate before calling

# shell: dry-run the same merge against Kubernetes to catch shape errors
kubectl patch pod <test-pod> --dry-run=server --type=strategic -p "$(cat podspec-patch.yaml)"
# Go: verify the patch unmarshals as a PodSpec before merging
var ps apiv1.PodSpec
b, _ := util.ConvertYAMLToJSON(patch)
if err := json.Unmarshal(b, &ps); err != nil { return fmt.Errorf("patch is not a PodSpec: %w", err) }

Try / catch

// Go: detect merge failures and point at patch shape
if _, err := util.ApplyPodSpecPatch(podSpec, patchYaml); err != nil {
	if strings.Contains(err.Error(), "Error occurred during strategic merge patch") {
		return fmt.Errorf("podSpecPatch structurally incompatible with PodSpec (lists like containers must be arrays merged by name): %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: Calling ApplyPodSpecPatch where podSpecJSON and podSpecPatchJSON are both valid JSON but the strategic merge cannot be computed — e.g. patch sets containers to a string instead of a list, or uses a map where patchMergeKey semantics require a list of objects.

Common situations: Writing podSpecPatch with containers as an object instead of an array; using incorrect types for fields (e.g. string "true" for a boolean); JSON/YAML conversion producing a shape Kubernetes can't merge; subtle mismatch after passing patches through multiple templating layers.

Related errors


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