🎉 DevOps Interview Prep Bundle is live — 1000+ Q&A across 20 topicsGet it →
All Articles

kubectl apply Field Manager Conflict Error: How to Fix It (2026)

How to resolve Kubernetes field manager conflict errors when using server-side apply — what causes them, how to identify the conflicting manager, and three different ways to fix it cleanly.

Shubham4 min read
Share:Tweet

If you have migrated to server-side apply or are using tools like ArgoCD, Helm, and kubectl alongside each other, you have probably hit this error at some point:

Apply failed with 1 conflict: conflict with "helm" using apps/v1:
  .spec.replicas

Or the longer form:

error: Apply failed with 2 conflicts: 
conflicts with "kubectl" using /v1: 
  - .metadata.annotations.kubectl.kubernetes.io/last-applied-configuration
conflicts with "helm" using apps/v1:
  - .spec.template.spec.containers[name="api"].image

These are field manager conflicts — a feature of server-side apply that prevents two different tools from accidentally overwriting each other's changes. Understanding the mechanism makes the fix straightforward.

What Server-Side Apply and Field Managers Are

Traditional kubectl apply (client-side apply) works by storing the last applied configuration in an annotation and doing a three-way merge locally in kubectl. It has no concept of ownership — whoever applies last wins.

Server-side apply (introduced in Kubernetes 1.18, stable in 1.22) moves this logic to the API server. The API server tracks which "field manager" owns each field in a resource. When you apply a change to a field owned by a different manager, Kubernetes returns a conflict error instead of silently overwriting.

This is protection, not a bug. But when you have multiple tools managing the same resource (ArgoCD + Helm, or kubectl + ArgoCD), you need to resolve the ownership question explicitly.

Diagnosing the Conflict

bash
# See the managed fields on a resource
kubectl get deployment my-app -o json | jq '.metadata.managedFields'

Output shows each manager, the fields they own, and when they last touched the resource:

json
[
  {
    "manager": "helm",
    "operation": "Apply",
    "apiVersion": "apps/v1",
    "time": "2026-07-01T10:00:00Z",
    "fieldsType": "FieldsV1",
    "fieldsV1": {
      "f:spec": {
        "f:replicas": {},
        "f:template": {
          "f:spec": {
            "f:containers": {
              "k:{\"name\":\"api\"}": {
                "f:image": {}
              }
            }
          }
        }
      }
    }
  },
  {
    "manager": "kubectl",
    "operation": "Apply",
    "apiVersion": "apps/v1",
    "time": "2026-07-05T14:00:00Z",
    "fieldsType": "FieldsV1",
    "fieldsV1": {
      "f:spec": {
        "f:replicas": {}
      }
    }
  }
]

Here you can see both helm and kubectl claim ownership of spec.replicas — that is the conflict.

Fix Option 1: Force Apply (Override the Conflict)

The simplest resolution — tell Kubernetes that your apply should win and take ownership from the previous manager:

bash
kubectl apply --server-side --force-conflicts -f deployment.yaml

This removes the ownership from the conflicting manager and assigns it to your current apply. Use this when:

  • The previous manager no longer exists or manages this resource
  • You are migrating from one tool to another (Helm → kubectl, or kubectl → ArgoCD)
  • You are the authoritative source and the conflict is from an old/stale manager

ArgoCD example — if ArgoCD is managing the resource but you need to apply a manual fix:

bash
kubectl apply --server-side --force-conflicts -f deployment.yaml --field-manager=argocd-application-controller

Fix Option 2: Remove the Conflicting Manager

If the other manager is no longer active (you stopped using Helm but its manager entry remains), clean it up:

bash
# Remove all managed fields from a specific manager
kubectl patch deployment my-app \
  --type=json \
  -p='[{"op": "remove", "path": "/metadata/managedFields/0"}]'

The index 0 is the position in the managedFields array. Check kubectl get deployment my-app -o json | jq '.metadata.managedFields | keys' to find the right index.

A cleaner approach for full cleanup:

bash
# Replace managedFields with just your manager
kubectl apply --server-side --force-conflicts \
  --field-manager=kubectl \
  -f deployment.yaml

This forces kubectl to take ownership of all fields in the manifest.

Fix Option 3: Use a Consistent Field Manager Name

The conflict often happens because different invocations use different manager names (kubectl vs kubectl-xxx vs argocd vs helm). If you are using ArgoCD + kubectl together, standardize:

bash
# Always use the same manager name when applying alongside ArgoCD
kubectl apply --server-side \
  --field-manager=kubectl \
  -f deployment.yaml

Or configure ArgoCD to use server-side apply with a specific manager:

yaml
# ArgoCD Application spec
apiVersion: argoproj.io/v1alpha1
kind: Application
spec:
  syncPolicy:
    syncOptions:
    - ServerSideApply=true

Fix Option 4: Convert Back to Client-Side Apply

If server-side apply is causing too many issues and you do not need its benefits, revert a resource to client-side apply:

bash
# Remove all managedFields (converts back to client-side)
kubectl patch deployment my-app \
  --type=merge \
  -p '{"metadata":{"managedFields":null}}'
 
# Then apply normally without --server-side
kubectl apply -f deployment.yaml

Avoiding Conflicts in CI/CD

If you use both Helm and kubectl apply in your pipelines, separate their concerns:

bash
# Option A: Always use --server-side with --force-conflicts in CI
kubectl apply --server-side --force-conflicts -f manifests/
 
# Option B: Use kubectl only for resources not managed by Helm/ArgoCD
# and let Helm/ArgoCD own everything else
 
# Option C: Migrate entirely to GitOps with ArgoCD — one tool owns all resources

The best long-term solution is single-tool ownership per resource. Having Helm manage the Deployment and kubectl patch it ad-hoc is the root cause of most field manager conflicts in practice.


More kubectl troubleshooting? Read our kubectl exec permission denied fix and ArgoCD sync stuck unknown fix.

Did this fix work?

Tell us what needs improving. No account required.

🔧

Today I Fixed

Short real fixes from production — posted daily

Browse fixes
Newsletter

Stay ahead of the curve

Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.

Related Articles

Comments