# cert-manager Certificate READY False: find the failing step

> A cert-manager Certificate stuck at READY False is failing in its CertificateRequest, Order or Challenge. Follow the chain with kubectl describe and fix it.

Source: https://ssl.sh/errors/cert-manager-certificate-not-ready/
Last updated: 2026-11-10

**A Certificate stuck at `READY False` means cert-manager has not obtained a signed certificate yet, and the reason is in one of the resources it created underneath.** For ACME issuers such as Let's Encrypt the chain is Certificate → CertificateRequest → Order → Challenge; the first resource in that chain that reports an error is the one to fix.

## Quick fix

The Challenge resource usually holds the CA's exact error message.

Walk down the chain in the Certificate's namespace:

```bash
kubectl describe certificate example-com -n web
kubectl get certificaterequest,order,challenge -n web
kubectl describe challenge -n web
kubectl describe clusterissuer letsencrypt-prod
```

The `Status` and `Events` of the Challenge usually contain the CA's exact message (for example a 404, a timeout, or a DNS problem). Fix that, then let cert-manager retry or delete the failed CertificateRequest to start over.

## Causes

Most stuck Certificates fail at the Challenge: an HTTP-01 path the CA cannot reach, or DNS-01 with wrong credentials or zones.

### 1. HTTP-01 challenge cannot be reached

The CA must fetch `http://<domain>/.well-known/acme-challenge/<token>` through your ingress. cert-manager creates a temporary solver pod, Service and Ingress for it.

- **Confirm:** the Challenge shows `Waiting for HTTP-01 challenge propagation` or an error like `wrong status code '404'`; `curl http://example.com/.well-known/acme-challenge/test` from outside never reaches the cluster.
- **Fix:** make the solver's `ingressClassName` (or class annotation) match your controller, expose port 80 on the controller's LoadBalancer, and exempt the challenge path from forced HTTPS redirects and authentication middleware. DNS for the name must point at the ingress load balancer.

### 2. DNS-01 credentials, zone or propagation

- **Confirm:** the Challenge reports API errors (`403`, `invalid credentials`), `NXDOMAIN`, or keeps waiting for propagation.
- **Fix:** check the Secret referenced by the solver and the provider permissions; make sure the solver targets the zone the domain is delegated to. When the cluster uses split-horizon DNS, configure the controller's `--dns01-recursive-nameservers` with public resolvers. See [NXDOMAIN](https://ssl.sh/errors/certbot-dns-problem-nxdomain/).

### 3. Issuer not Ready or referenced wrongly

- **Confirm:** `kubectl get issuer,clusterissuer -A` shows READY False, or the CertificateRequest says the issuer was not found.
- **Fix:** an `Issuer` is namespaced and only serves Certificates in the same namespace; use `kind: ClusterIssuer` in `issuerRef` for a cluster-wide issuer. Check the ACME `server` URL, email and private key Secret.

### 4. The CA refuses the order

- **Confirm:** the Order or CertificateRequest message contains `rateLimited`, `caa`, or `rejectedIdentifier`.
- **Fix:** see [Let's Encrypt rate limits](https://ssl.sh/errors/lets-encrypt-rate-limit/) and [CAA record prevents issuance](https://ssl.sh/errors/caa-record-prevents-issuance/). Names that are not valid public DNS names cannot be issued by a public CA.

### 5. Secret or webhook problems

- **Confirm:** events mention a conflict with an existing Secret, or the cert-manager webhook is unreachable (`failed calling webhook`).
- **Fix:** make sure only one Certificate manages a given `secretName`; check that the cert-manager, cainjector and webhook pods are running and that network policies allow the API server to reach the webhook.

## Fixes by environment

The failing step is found the same way everywhere; what differs is how the challenge reaches the CA through an ingress, a Gateway or a load balancer.

**Ingress-based annotation (`cert-manager.io/cluster-issuer`):** cert-manager's ingress-shim creates the Certificate for you; describe it by the name of the `tls.secretName`.

**Gateway API:** HTTP-01 through Gateway API needs the solver configured with `gatewayHTTPRoute` and a Gateway listener on port 80.

**Private clusters and clusters behind NAT:** HTTP-01 needs a public route to port 80; otherwise use DNS-01.

**Cloud load balancers:** health checks or WAF rules on the load balancer can block or redirect challenge requests; exempt the path.

**Staging first:** a staging ClusterIssuer avoids burning production limits while you debug.

## Don't do this

- **Delete and recreate the Certificate in a loop.** Each new Order counts toward CA limits; fix the failing step first.
- **Disable HTTPS redirects globally** to let the challenge through. Exempt `/.well-known/acme-challenge/` only.
- **Copy a certificate into the Secret by hand** and leave the Certificate broken. It will not renew, and it will expire silently.
