kubernetes/kops · error

error patching status: %w

Error message

error patching status: %w

What it means

In the KopsConfig bootstrap controller's Reconcile, after storing the bootstrap-data secret, the controller updates the KopsConfig object's status (DataSecretName, Ready) with client.Status().Update. This error wraps any failure of that status update — most commonly an optimistic-concurrency conflict because the object changed since it was fetched.

Source

Thrown at pkg/controllers/clusterapi/kopsconfig_controller.go:107

		return ctrl.Result{}, err
	}

	kopsControlPlane, err := getKopsControlPlaneFromCAPICluster(ctx, r.client, capiCluster)
	if err != nil {
		return ctrl.Result{}, err
	}

	data, err := r.buildBootstrapData(ctx, cluster, kopsControlPlane)
	if err != nil {
		return ctrl.Result{}, err
	}

	if err := r.storeBootstrapData(ctx, obj, data); err != nil {
		return ctrl.Result{}, err
	}

	if err := r.client.Status().Update(ctx, obj); err != nil {
		return ctrl.Result{}, fmt.Errorf("error patching status: %w", err)
	}
	return ctrl.Result{}, nil
}

// storeBootstrapData creates a new secret with the data passed in as input,
// sets the reference in the configuration status and ready to true.
func (r *KopsConfigReconciler) storeBootstrapData(ctx context.Context, parent *api.KopsConfig, data []byte) error {
	// log := ctrl.LoggerFrom(ctx)

	clusterName := parent.Labels[clusterv1.ClusterNameLabel]

	if clusterName == "" {
		return fmt.Errorf("cluster name label %q not yet set", clusterv1.ClusterNameLabel)
	}

	secretName := types.NamespacedName{
		Namespace: parent.GetNamespace(),
		Name:      parent.GetName(),

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Simply requeue — controller-runtime retries and the conflict resolves on the next reconcile with fresh resourceVersion
  2. Use a merge patch (client.Status().Patch with client.MergeFrom) to reduce conflict likelihood
  3. Grant update/patch on kopsconfigs/status to the controller ServiceAccount
  4. Check API-server health/etcd latency if conflicts persist at scale

Example fix

// before
if err := r.client.Status().Update(ctx, obj); err != nil {
    return ctrl.Result{}, fmt.Errorf("error patching status: %w", err)
}
// after: use patch to reduce optimistic-concurrency conflicts
patch := client.MergeFrom(obj.DeepCopy())
obj.Status.DataSecretName = pointer.String(secret.Name)
obj.Status.Ready = true
if err := r.client.Status().Patch(ctx, obj, patch); err != nil {
    if apierrors.IsConflict(err) {
        return ctrl.Result{RequeueAfter: time.Second}, nil
    }
    return ctrl.Result{}, fmt.Errorf("error patching status: %w", err)
}
Defensive patterns

Strategy: retry

Validate before calling

kubectl auth can-i patch kopsconfigs.status -n <ns> --as=system:serviceaccount:<ns>:<sa>
# or: kubectl auth can-i update kopsconfigs/status ...

Try / catch

if err := r.client.Status().Update(ctx, obj); err != nil {
    if apierrors.IsConflict(err) {
        return ctrl.Result{Requeue: true}, nil // stale resourceVersion, retry with fresh copy
    }
    return ctrl.Result{}, fmt.Errorf("error patching status: %w", err)
}

Prevention

When it happens

Trigger: The KopsConfig object was modified (resourceVersion bumped) between the initial Get and the Status().Update, producing a Conflict; the ServiceAccount lacks update permission on kopsconfigs/status; the API server rejects or times out the request.

Common situations: Frequent reconcile storms where the object is edited concurrently by another controller or user; controller RBAC missing status-update verbs; API server slowness/etcd timeouts.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/13cd2d9595ec018d. Report an issue: GitHub.