Handle server-side-apply conflicts safely
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 deploy how-to-adoption-takeover --reconcile --dry-run -y
⚠ Deployment/legacy-web@takeover field-ownership conflict on Deployment/legacy-web@takeover: another field manager owns one or more fields kix is trying to set. Re-run with --force-conflicts to take ownership. Underlying error: 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: field-ownership conflict on Deployment/legacy-web@takeover: another field manager owns one or more fields kix is trying to set. Re-run with --force-conflicts to take ownership. Underlying error: 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 asks the API server to validate the 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.
By default, the run stops after this conflict and ends with 1 failed, 4 cancelled. The cancelled resources have not been checked. To find conflicts
on the remaining resources, run the dry run again with --on-error continue:
❱ kix deploy how-to-adoption-takeover --reconcile --dry-run -y --on-error continue This still skips resources that depend on a failed resource, but continues checking independent branches of the dependency graph.
Inspect the other manager
Section titled “Inspect the other manager”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.
Choose the field owner
Section titled “Choose the field owner”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.
Preview the ownership transfer
Section titled “Preview the ownership transfer”Once Kix is the intended owner, add --force-conflicts to the same dry run:
❱ 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.
Apply the resolution
Section titled “Apply the resolution”Run the reconciled deployment with the same flag:
❱ 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-nphkg40wdk30' → 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.