cilium/cilium · error

failed to update CiliumCIDRGroup %s: %w

Error message

failed to update CiliumCIDRGroup %s: %w

What it means

updateCCG updates an existing CiliumCIDRGroup via the Kubernetes API after a prior create returned AlreadyExists (or direct update path). If the Update call fails for reasons other than triggering a create, the error is logged at Warn and wrapped as 'failed to update CiliumCIDRGroup <name>: %w'. This indicates the existing group could not be brought to the desired CIDR set.

Source

Thrown at operator/pkg/networkpolicy/external-groups/cidrgroup.go:219

		logfields.Name, ccg.Name,
	)
	return ccg, nil
}

// updateCCG updates an existing CiliumCIDRGroup in the apisever.
// falls back to Create if the group does not exist for some reason.
func (gm *externalGroupManager) updateCCG(ctx context.Context, ccg *apiv2.CiliumCIDRGroup) (*apiv2.CiliumCIDRGroup, error) {
	ccg, err := gm.clientset.CiliumV2().CiliumCIDRGroups().Update(ctx, ccg, metav1.UpdateOptions{FieldManager: FieldManager})
	if apierrors.IsNotFound(err) {
		gm.log.Warn("CiliumCIDRGroup for external group was unexpectedly deleted",
			logfields.Name, ccg.Name)
		return gm.createCCG(ctx, ccg)
	}
	if err != nil {
		gm.log.Warn("Failed to update CiliumCIDRGroup for external Group",
			logfields.Name, ccg.Name,
			logfields.Error, err)
		return nil, fmt.Errorf("failed to update CiliumCIDRGroup %s: %w", ccg.Name, err)
	}
	gm.log.Info("Updated CiliumCIDRGroup for external Group",
		logfields.Name, ccg.Name,
	)
	return ccg, nil
}

func (gm *externalGroupManager) deleteCCG(ctx context.Context, name string) error {
	// Delete the underlying CCG
	err := gm.clientset.CiliumV2().CiliumCIDRGroups().Delete(ctx, name, metav1.DeleteOptions{})
	if err != nil && !apierrors.IsNotFound(err) {
		gm.log.Warn("Failed to delete stale CiliumCIDRGroup for external Group",
			logfields.Name, name,
			logfields.Error, err)
		return fmt.Errorf("failed to delete CiliumCIDRGroup %s: %w", name, err)
	}
	gm.log.Info("Deleted stale CiliumCIDRGroup for external group",
		logfields.Name, name)

View on GitHub (pinned to ac7b90affa)

Solutions

  1. If the error is a Conflict, re-fetch the latest CiliumCIDRGroup and retry the update with a fresh resourceVersion (Retry-On-Conflict).
  2. Verify the object still exists: kubectl get ciliumcidrgroup <name>; if missing, go through createCCG again.
  3. Grant the operator update permission on ciliumcidrgroups.cilium.io.
  4. Inspect the wrapped %w cause for the precise API error and act on it.

Example fix

// before
_, err = gm.updateCCG(ctx, ccg) // stale resourceVersion -> conflict
// after
latest, err := gm.clientset.CiliumV2().CiliumCIDRGroups().Get(ctx, ccg.Name, metav1.GetOptions{})
if err != nil { return nil, err }
latest.CIDRGroups = ccg.CIDRGroups
_, err = gm.updateCCG(ctx, latest)
Defensive patterns

Strategy: retry

Validate before calling

latest, err := gm.clientset.CiliumV2().CiliumCIDRGroups().Get(ctx, ccg.Name, metav1.GetOptions{})
if err != nil { return err }
ccg.ResourceVersion = latest.ResourceVersion

Type guard

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

Try / catch

err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
  latest, err := gm.clientset.CiliumV2().CiliumCIDRGroups().Get(ctx, ccg.Name, metav1.GetOptions{})
  if err != nil { return err }
  latest.CIDRGroups = ccg.CIDRGroups
  _, err = gm.updateCCG(ctx, latest)
  return err
})

Prevention

When it happens

Trigger: gm.clientset.CiliumV2().CiliumCIDRGroups().Update returns an error — commonly a Conflict/OptimisticConcurrency (resourceVersion changed) or Forbidden/NotFound — while called from upsertCCG after the create attempt found the object already exists.

Common situations: Another controller or a user edited the CiliumCIDRGroup concurrently so resourceVersion is stale (typical conflict); RBAC missing update permission; the group was deleted between create and update; stale local cache of the object.

Related errors


AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31). Data as JSON: /api/errors/3ac7fca96ec7d2a2. Report an issue: GitHub.