kubernetes/kubernetes · warning

unable to delete PodCertificateRequest %q: %w

Error message

unable to delete PodCertificateRequest %q: %w

What it means

Returned by the PodCertificateRequest cleaner controller's handle function when deleting a PCR that is older than the configured threshold fails. Unlike the CSR cleaner, this code properly handles NotFound (line 100-102) before wrapping the error, so only genuine deletion failures (permission, API errors) produce this error. The %w verb preserves the error chain for unwrapping.

Source

Thrown at pkg/controller/certificates/cleaner/pcrcleaner.go:104

}

func (c PCRCleanerController) handle(ctx context.Context, pcr *certsv1.PodCertificateRequest) error {
	if c.clock.Now().Before(pcr.ObjectMeta.CreationTimestamp.Time.Add(c.threshold)) {
		return nil
	}

	opts := metav1.DeleteOptions{
		Preconditions: &metav1.Preconditions{
			UID: ptr.To(pcr.ObjectMeta.UID),
		},
	}

	err := c.client.CertificatesV1().PodCertificateRequests(pcr.ObjectMeta.Namespace).Delete(ctx, pcr.ObjectMeta.Name, opts)
	if k8serrors.IsNotFound(err) {
		// This is OK, we don't care if someone else already deleted it.
		return nil
	} else if err != nil {
		return fmt.Errorf("unable to delete PodCertificateRequest %q: %w", pcr.ObjectMeta.Namespace+"/"+pcr.ObjectMeta.Name, err)
	}

	return nil
}

View on GitHub (pinned to 94c1367642)

Solutions

  1. Check the wrapped error — if it is a Conflict (apierrors.IsConflict), the UID precondition failed because the PCR was replaced; this is benign.
  2. Verify the controller manager's ClusterRole includes 'delete' on 'podcertificaterequests'.
  3. Ensure the PodCertificateRequests feature gate is enabled and the API is available in the cluster version.
  4. If errors persist, check API server health and the PCR API registration.
Defensive patterns

Strategy: retry

Try / catch

// The PCR cleaner already handles NotFound. If building custom cleanup:
if err := client.CertificatesV1().PodCertificateRequests(ns).Delete(ctx, name, opts); err != nil {
    if k8serrors.IsNotFound(err) {
        return nil // already cleaned
    }
    if k8serrors.IsConflict(err) {
        // UID precondition failed — PCR was replaced
        return nil
    }
    return fmt.Errorf("unable to delete PodCertificateRequest %q: %w", ns+"/"+name, err)
}

Prevention

When it happens

Trigger: The cleaner identifies a PodCertificateRequest older than the threshold and calls client.CertificatesV1().PodCertificateRequests(namespace).Delete(ctx, name, opts) with a UID precondition. The delete fails with a non-NotFound error: permission denied, API server error, or UID mismatch (Conflict, since the PCR was recreated with a different UID).

Common situations: The controller manager lacks RBAC permission to delete podcertificaterequests. The PCR was deleted and a new one with the same name but different UID was created (UID precondition Conflict). API server connectivity issues during the cleanup polling interval.

Understand the failure class

Related errors


AI-assisted analysis of kubernetes/kubernetes@94c1367642 (2026-08-08). Data as JSON: /api/errors/14917bc10b62834d. Report an issue: GitHub.