kubernetes/kops · error

error updating object: %w

Error message

error updating object: %w

What it means

Update wraps errors from the dynamic resource client's Update call. Like the patch wrapper, it preserves the underlying API error; failures usually mean the object changed on the server (conflict), is invalid, or the request was rejected.

Source

Thrown at pkg/applylib/applyset/unstructuredclient.go:104

	name := nn.Name
	patched, err := dynamicResource.Patch(ctx, name, patchType, data, opt)
	if err != nil {
		return nil, fmt.Errorf("error patching object: %w", err)
	}
	return patched, nil
}

// Update performs an Update operation on the object.  Generally we should prefer server-side-apply.
func (c *UnstructuredClient) Update(ctx context.Context, obj *unstructured.Unstructured, opt metav1.UpdateOptions) (*unstructured.Unstructured, error) {
	gvk := obj.GroupVersionKind()
	dynamicResource, err := c.dynamicResource(ctx, gvk, obj.GetNamespace())
	if err != nil {
		return nil, err
	}

	updated, err := dynamicResource.Update(ctx, obj, opt)
	if err != nil {
		return nil, fmt.Errorf("error updating object: %w", err)
	}
	return updated, nil
}

// Get reads the specified object.
func (c *UnstructuredClient) Get(ctx context.Context, gvk schema.GroupVersionKind, nn types.NamespacedName) (*unstructured.Unstructured, error) {
	dynamicResource, err := c.dynamicResource(ctx, gvk, nn.Namespace)
	if err != nil {
		return nil, err
	}

	obj, err := dynamicResource.Get(ctx, nn.Name, metav1.GetOptions{})
	if err != nil {
		return nil, fmt.Errorf("could not get existing object: %w", err)
	}

	return obj, nil
}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Get a fresh copy of the object, re-apply your changes onto it, and retry Update (handles resourceVersion conflicts)
  2. Inspect the wrapped error with apierrors.IsConflict/IsInvalid/IsForbidden to branch appropriately
  3. For declarative workflows prefer server-side apply (Patch with ApplyPatchType) over Update to reduce conflicts
  4. Fix invalid object fields flagged by the API server before retrying

Example fix

// before
updated, err := client.Update(ctx, obj, metav1.UpdateOptions{})
// after
updated, err := client.Update(ctx, obj, metav1.UpdateOptions{})
if err != nil {
	if apierrors.IsConflict(err) {
		// re-fetch obj, reapply change, retry with backoff
	}
	return updated, err
}
Defensive patterns

Strategy: retry

Validate before calling

if obj.GetNamespace() == "" && requiresNamespace(gvk) {
	return fmt.Errorf("pre-check: object %s needs a namespace before update", gvk.Kind)
}

Type guard

func isUpdateConflict(err error) bool {
	return apierrors.IsConflict(errors.Unwrap(err))
}

Try / catch

err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
	fresh, err := client.Get(ctx, gvk, nn)
	if err != nil {
		return err
	}
	applyChanges(fresh)
	_, err = client.Update(ctx, fresh, metav1.UpdateOptions{})
	return err
})

Prevention

When it happens

Trigger: Calling UnstructuredClient.Update on an unstructured object where the API server rejects the write: 409 Conflict on stale resourceVersion, 422 validation failure, 403 RBAC denial, or object not found.

Common situations: Optimistic-concurrency conflicts when another controller (or the same apply loop) modified the object; editing objects with defaulted/immutable fields; concurrent apply-set workers updating the same resource.

Related errors


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