Skip to content
kix /docs
Install the CLI

How-to guide Adopt existing resources

Handle server-side-apply conflicts safely

Identify the competing field manager and resolve a Kix server-side apply conflict deliberately.

A server-side apply conflict means Kix is trying to change a field owned by another field manager. Identify that manager and decide who should own the field before forcing a deployment.

The example below starts with a Kix-managed Deployment. A separate manager named autoscaler then takes ownership of spec.replicas and changes it from two to three.

Reproduce the conflict without changing the cluster

Section titled “Reproduce the conflict without changing the cluster”

Run a reconciled API-server dry run:

kix-examples/ output excerpt
❱ kix deploy how-to-adoption-takeover --reconcile --dry-run -y
⚠ Deployment/legacy-web@takeover cannot update Deployment/legacy-web@takeover: another tool owns fields that Kix is trying to change. Review the fields listed below. If Kix should manage them, rerun with --force-conflicts to take ownership; if the other tool is meant to own them, declare them on the resource with `ownership.cede`. Kubernetes reported: ApiError: Apply failed with 1 conflict: conflict with "autoscaler": .spec.replicas: Conflict (ErrorResponse { status: "Failure", message: "Apply failed with 1 conflict: conflict with \"autoscaler\": .spec.replicas", reason: "Conflict", code: 409 })
✗ halt-on-first-failure: cannot update Deployment/legacy-web@takeover: another tool owns fields that Kix is trying to change. Review the fields listed below. If Kix should manage them, rerun with --force-conflicts to take ownership; if the other tool is meant to own them, declare them on the resource with `ownership.cede`. Kubernetes reported: ApiError: Apply failed with 1 conflict: conflict with "autoscaler": .spec.replicas: Conflict (ErrorResponse { status: "Failure", message: "Apply failed with 1 conflict: conflict with \"autoscaler\": .spec.replicas", reason: "Conflict", code: 409 })
Dry run complete: 0 created, 5 configured, 0 unchanged, 1 failed, 4 cancelled
(exit code: 1)

--reconcile makes Kix check every resource even when the activation itself has not changed. --dry-run runs kix plan, which asks the API server to validate each apply without persisting it.

Read the conflict message closely. It identifies three things:

  • the resource, Deployment/legacy-web@takeover;
  • the other field manager, autoscaler;
  • the overlapping field, .spec.replicas.

The dry run carries on past a conflict and still checks the resources that depend on the conflicting one, so the plan lists every conflict in one run. It exits 3, the status for a deploy that would stop. A real deploy with the same conflicts stops before applying anything under the default --on-error stop.

Fetch the resource with its managed fields:

❱ kubectl get deployment legacy-web -n takeover -o yaml --show-managed-fields

Find the named manager under metadata.managedFields, then determine what owns it. Common managers include an operator, an autoscaler, kubectl, Helm, and another deployment system.

Also inspect the current field value and the Kix definition. A conflict is not evidence that the other value is wrong.

If the other controller should continue managing the field, change the Kix package or its configuration so it no longer emits that field. When the package cannot omit it, because the field is required on create or the whole object comes from upstream, declare the field as ceded on the resource:

scope.mkResource {
# ...
ownership.cede = [ "spec.replicas" ];
}

Kix stamps the paths as kix.run/cede-fields. When a later apply conflicts only on those paths, deploy retries without them and the other manager keeps the field; a conflict anywhere else still fails. See Cede fields to a controller. Choose one manager either way, rather than letting both repeatedly take ownership from each other.

If Kix should manage the field, first disable or reconfigure the other manager for this resource. Otherwise the conflict will return after both systems reconcile again.

Once Kix is the intended owner, add --force-conflicts to the same dry run:

kix-examples/ output excerpt
❱ kix deploy how-to-adoption-takeover --reconcile --dry-run --force-conflicts -y
~ Deployment/legacy-web@takeover configured
✔ Deployment/legacy-web@takeover ready
Dry run complete: 0 created, 10 configured, 0 unchanged, 0 failed

This confirms that the API server accepts the transfer while still writing nothing. Review the rest of the plan before continuing.

Run the reconciled deployment with the same flag:

kix-examples/ output excerpt
❱ kix deploy how-to-adoption-takeover --reconcile --force-conflicts -y
~ Deployment/legacy-web@takeover configured
✔ Deployment/legacy-web@takeover ready
• activation 'how-to-adoption-takeover-3gdjlxrhh7h4' → Active
Deploy complete: 0 created, 10 configured, 0 unchanged, 0 failed

The successful apply transfers the overlapping field to the kix field manager and restores the replica count from the Kix definition.

Return to ordinary deployments after resolving the conflict. Keeping --force-conflicts in routine commands can hide a new ownership dispute that needs a separate decision.