Skip to content

Strategic merge patch inherits base YAML string tag, corrupting integer values on IntOrString fields #6140

Description

@CDillinger

Summary

When a strategic merge patch replaces a value on an IntOrString field (e.g., maxUnavailable, maxSurge), kustomize preserves the YAML string tag (!!str) from the base node rather than using the tag from the patch node. This causes integer patch values to be emitted as quoted strings in the output, which Kubernetes rejects.

Reproduction

Given a base with an explicitly quoted string value:

# base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test
spec:
  strategy:
    rollingUpdate:
      maxSurge: 50%
      maxUnavailable: '6%'   # <-- explicitly quoted

And a strategic merge patch with an integer:

# patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test
spec:
  strategy:
    rollingUpdate:
      maxUnavailable: 3          # <-- integer
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - deployment.yaml
patches:
  - path: patch.yaml

Expected output

maxUnavailable: 3

Actual output

maxUnavailable: "3"

Kubernetes rejects this:

The Deployment "test" is invalid: spec.strategy.rollingUpdate.maxUnavailable:
Invalid value: intstr.IntOrString{Type:1, IntVal:0, StrVal:"3"}:
a valid percent string must be a numeric string followed by an ending '%'

Key finding

The behavior depends on whether the base value is explicitly quoted in YAML:

Base value Patch value Output Valid?
maxUnavailable: 6% (unquoted) 3 maxUnavailable: 3
maxUnavailable: '6%' (quoted) 3 maxUnavailable: "3"
maxUnavailable: "6%" (quoted) 3 maxUnavailable: "3"

When the base node has an explicit YAML string tag (from quoting), the strategic merge patch preserves that tag on the replaced value instead of adopting the patch node's tag.

Expected behavior

When a strategic merge patch replaces a scalar value, the output should use the patch node's YAML tag, not the base node's tag. The patch is providing a new value — it should also provide the new type.

Workarounds

  1. Use a JSON patch (op: replace) instead of a strategic merge patch — JSON patches correctly emit the integer.
  2. Remove explicit quotes from the base value (use 6% not '6%').

Environment

  • kustomize v5.8.1 (also reproduced with v5.6.0 via go library)
  • macOS / Linux

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-kindIndicates a PR lacks a `kind/foo` label and requires one.triage/acceptedIndicates an issue or PR is ready to be actively worked on.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions