🎉 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.

🔧

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