ACME failures are usually terse, and the useful part is buried in a URN that looks like noise. This guide explains what each of the common errors actually means, where in the process it happens, and what to change. The errors are grouped by which leg of the exchange broke, because that is what decides where to look, and getting the direction wrong is the most common reason people fix the wrong thing.
How to read an ACME error
Every ACME server returns errors in a standard shape, so even an error not listed on this page can be placed. The response carries a type, which is the URN, and a detail, which is free text written by that particular CA. The type tells you the category; the detail usually names the specific host, record or file involved.
Two habits save most of the guesswork. First, turn on the client’s own logging before you start changing configuration:
acme.sh --issue -d example.com --server https://acme.yourca.example/v2/DV --debug
Second, note whether the failure happened before or after the CA tried to validate the domain. Anything about accounts, keys or signatures happened before, in the conversation between your client and the CA. Anything about challenges, files, records or connections happened after, when the CA came looking for proof. The sections below follow that split.
Account and registration errors
externalAccountRequired: External Account Binding missing or invalid
The full type is urn:ietf:params:acme:error:externalAccountRequired, defined as the request having to include a value for the external account binding field. The CA requires you to prove you already hold an account with them, and your client either sent nothing or sent something it rejected. Every commercial CA works this way; Let’s Encrypt does not use EAB at all.
- Pass both credentials. With acme.sh the flags are
--eab-kidand--eab-hmac-key, with two hyphens. Guides that render them with a single long dash are a frequent source of “unrecognised option” confusion. - Do not re-encode the HMAC key. It is already base64url as the CA gives it to you. acme.sh rejects a mangled value with a message about being unable to base64-decode the key, and other clients say the same thing in their own words. Check for a trailing space or a line break introduced by copying.
- Use the directory URL that matches the credentials. EAB credentials are issued against a specific endpoint, so a production key will not register against a staging directory or vice versa.
- Check whether the credentials are single use. Many CAs mint EAB credentials that are valid for one registration, so a second attempt after a failure needs a fresh pair.
badSignatureAlgorithm: the HMAC algorithm does not match
Defined as the request being signed with an algorithm the server does not support. This one is worth knowing precisely because it looks exactly like a wrong password: the key identifier and the HMAC key are both correct, and registration still fails.
External Account Binding is signed with an HMAC algorithm, and clients pick a default. win-acme, for example, defaults to HS256 and also accepts HS384 and HS512. If your CA expects one of the others, the binding is refused. Ask the CA which algorithm its endpoint expects and set it explicitly if the client offers the option.
accountDoesNotExist: the CA does not recognise your account key
Your client is presenting a locally stored account key that the CA has no record of. It typically follows a client reinstall, a move to a new server, a restored backup, or a switch between staging and production endpoints, since each endpoint holds its own accounts.
acme.sh --register-account \
--server https://acme.yourca.example/v2/DV \
--eab-kid "YOUR_EAB_KEY_ID" \
--eab-hmac-key "YOUR_EAB_HMAC_KEY" \
--accountemail "[email protected]"
Register again against the endpoint you actually order from, and avoid copying account files between hosts or clients unless you are certain they belong to the same CA and the same environment. Account state is not portable in the way certificate files are.
badNonce: the anti-replay token was rejected
Defined as the client sending an unacceptable anti-replay nonce. Under RFC 8555 the server issues a nonce, marks it invalid the moment it is used, and when it rejects one it must return a fresh nonce in the same response for the client to retry with. Clients are expected to do exactly that automatically, which is why this error is usually invisible.
If it does surface, retry the command; it normally succeeds on the second attempt. Repeated failures point at a nonce being reused rather than refreshed: two ACME processes running against the same account at once, or a proxy or CDN in front of your outbound requests that retries POSTs on your behalf. Take the intermediary out of the path and try again.
You will find advice that badNonce is caused by a wrong system clock. The nonce is an opaque value the server issues and tracks, with no timestamp for your clock to disagree with, so that is not the mechanism. A badly wrong clock does break ACME, but it does so earlier and differently, by failing the TLS connection to the CA. If your client cannot reach the CA at all, then checking the clock is worthwhile:
timedatectl status
sudo timedatectl set-ntp true
Validation errors: the CA could not verify the domain
unauthorized: the challenge could not be read
The CA reached your server but did not get what it needed, often reported alongside a line naming the exact URL it tried, such as an invalid response from http://example.com/.well-known/acme-challenge/ followed by the token.
- Make sure the name is reachable on port 80 from the public internet, even if your site normally redirects to HTTPS. The CA follows redirects, so a redirect is fine; a blocked port is not.
- Check that the web root configured in your client is the one the site actually serves. A challenge written to the wrong directory produces this error with a perfectly healthy web server.
- Look for rules that block the /.well-known/ path: security plugins, .htaccess rules, a WAF, or a CDN serving a cached 404.
- Confirm the file is world readable, along with its parent directories.
Token not found: 404 or 403 on the challenge file
A more specific case of the above, and the status code narrows it usefully. A 404 means the file is not where the CA looked, so compare the document root against the path your client writes to. A 403 means it is there but the server refuses to serve it, which points at file ownership, directory permissions, or a security layer such as SELinux or AppArmor.
Test it yourself before changing anything. Open the challenge URL in a browser, or fetch it from a machine outside your network. If you can read the token and the CA cannot, the problem is between them and you, not on disk.
incorrectResponse: the file was served but the content was wrong
Defined as the response received not matching the challenge’s requirements. This is the one people misread as a permissions problem, because the request succeeded. Something answered, just not with the token.
The usual causes are a catch-all rule that returns the site’s index page or a friendly 404 page for any unknown path, a CDN serving a stale copy of an earlier challenge, or two servers behind a load balancer where only one of them has the file. Check what the URL actually returns rather than whether it returns something.
connection: the CA could not reach your server at all
Defined as the server being unable to connect to the validation target. Note the direction: this is the CA failing to reach you, which is a different problem from your client failing to reach the CA further down this page, and the two get confused constantly.
Check that the name resolves to the address you expect from outside your own network, that the relevant port is open through every firewall and NAT device in front of the server, and that the host is not behind CGNAT. If it is unreachable by design, stop trying to fix HTTP validation and switch that name to a DNS challenge, which requires no inbound connection.
TXT record not found, for DNS validation and wildcards
Reported as a dns error, defined as a problem with a DNS query during identifier validation, and often shown as NXDOMAIN looking up TXT for _acme-challenge.example.com. Wildcards can only be validated this way, so wildcard requests meet it most.
Create a TXT record named _acme-challenge under the name being validated, with the token value the client printed, and confirm it is visible publicly before retrying:
dig TXT _acme-challenge.example.com +short
Two things make this fail repeatedly rather than once. The token is unique per request, so re-running the client generates a new one and the record you added a moment ago is already stale. And propagation is not instant, so a client that checks too quickly gives up before the record is live. Both are solved by letting the client manage the record through your DNS provider’s API instead of publishing it by hand, which also means renewals work unattended.
Policy errors: the name itself was refused
caa: a CAA record forbids this CA
Defined as CAA records forbidding the CA from issuing. Certificate authorities are required to check CAA before issuing, so this is a DNS policy decision rather than anything wrong with your server. Inspect what is published:
dig CAA example.com +short
No record means any CA may issue. If there is one, it has to name an identifier your CA actually publishes, and this is where the error usually comes from: people guess the identifier from the brand name. Sectigo recognises exactly three, sectigo.com, trust-provider.com and usertrust.com, in the issue, issuewild and issuemail tags. DigiCert publishes a longer list that includes digicert.com along with legacy brands such as thawte.com, geotrust.com, rapidssl.com and symantec.com, and states that all of them are equivalent. Retired brand names that a CA never listed, or listed under a previous owner, block issuance exactly as effectively as naming a competitor. Check your CA’s own published list rather than inferring it.
example.com. IN CAA 0 issue "sectigo.com"
example.com. IN CAA 0 issuewild "sectigo.com"
Use straight double quotes. Curly quotation marks pasted from a web page or a word processor produce a record the DNS provider either rejects or stores with the wrong value, and the symptom is identical to having no record at all. You do not need a separate issuewild record for a wildcard: under RFC 8659 an issue record authorises wildcard issuance as well, and the example above is simply the belt-and-braces form. What does bite is the precedence rule. If any issuewild record exists, it replaces issue for wildcard requests, so an issuewild naming a different authority, or the issuewild ";" form that forbids wildcards outright, blocks your wildcard while ordinary names keep working. Allow a few minutes for the change to propagate before retrying.
rejectedIdentifier: the CA will not accept that name
The CA refused one or more of the names in the request, before any validation was attempted. Work through these in order:
- Send a bare host name. It is -d example.com, not a URL. A protocol, a trailing slash or a path makes the identifier invalid.
- Confirm the name exists publicly with dig example.com +short. Internal-only names cannot be validated by a public CA at all.
- Check the name is on the order. With a commercial certificate the names are fixed when the order is placed, so you cannot add one at issuance time the way a free CA allows.
- Watch for near misses. example.com and www.example.com are separate identifiers and both must be listed if both are used.
dns: the name does not resolve
Messages such as NXDOMAIN looking up A for a host, or a temporary failure in name resolution, mean the CA could not resolve the name to an address. Confirm the A or AAAA records exist and are visible from outside your network, and remember that a name which resolves on your own machine may be answered by an internal resolver or a hosts file entry that the CA cannot see. New domains and recent DNS changes need time to propagate.
Transient and client-side errors
rateLimited: too many requests
The CA is refusing further requests for now, sometimes as an HTTP 429. It follows repeated requests for the same names or a run of failed attempts, and the limits and reset periods are set by each CA rather than by the protocol, so check your CA’s documentation for the specific one you hit.
The useful discipline is to stop retrying and fix the underlying failure first, because failed attempts count too and looping on them extends the lockout. If you are testing a setup, use the CA’s staging or test endpoint, which exists precisely so that experiments do not consume production limits.
orderNotReady: finalizing too early
Defined as an attempt to finalize an order that is not ready to be finalized. Every identifier on the order has to be validated before the CSR is submitted, so this appears when one name in a multi-name order is still pending or has failed while the others succeeded. Look for the authorization that has not completed rather than at the finalize step itself; the fix is always in the validation of that one name.
badCSR: the request itself is unacceptable
The CA rejected the certificate signing request, most often because the key is too short or uses an algorithm the CA does not accept for that product, or because the names in the CSR do not match the names on the order. Most ACME clients generate the CSR for you, so this usually appears when a CSR is supplied by hand.
Your client cannot reach the ACME server
Connection refused, timeout during connect, or a similar message from the client rather than a URN from the CA. This is the outbound direction, the mirror image of the connection error above.
- Confirm the host allows outbound HTTPS on port 443, which is often restricted on hardened or cloud-hosted servers.
- Check that the host has a working DNS resolver, and that any outbound proxy permits the CA’s hostname.
- Test the endpoint directly, which also proves TLS works and therefore that the clock is close enough to be trusted.
curl -sS -o /dev/null -w "%{http_code}\n" https://acme.yourca.example/v2/DV
The certificate renewed but nothing started using it
Not an ACME error at all, and the most commonly reported problem in this whole area. Renewal writes new files; it does not tell a running service to re-read them. If your deploy hook or post-renewal script fails, or was never configured, the certificate on disk is current while the one being served is not, and nobody notices until it expires.
- Run the script by hand and read what it prints, rather than trusting that it ran.
- Check it is executable and that the paths inside it point at the current certificate files.
- Remember that the script runs from the renewal process, not your interactive shell, so it does not inherit your environment or your working directory.
- Prefer a deploy hook your client already ships for the platform over a script you maintain, since the built-in ones are kept working as the target’s API changes.
- Force one renewal deliberately and confirm the service picks the new certificate up, rather than discovering the gap at expiry.
Frequently Asked Questions
It is the namespace RFC 8555 defines for machine-readable ACME error types. The final word identifies the problem, and every CA uses the same vocabulary, so badNonce means the same thing whichever authority returned it. The accompanying detail text is written by that CA and is where the specific host name, record or file is usually named.
Check three things in this order. Whether the HMAC key was altered by copying, since it is already base64url encoded and must be passed through untouched. Whether the directory URL matches the endpoint the credentials were issued for. And whether the CA expects a different HMAC algorithm from your client’s default, which surfaces as badSignatureAlgorithm and looks exactly like bad credentials.
No. A nonce is an opaque value the CA issues and then treats as spent, with no timestamp involved, and the specification requires the CA to return a fresh one for the client to retry with. Retry the command. A badly wrong clock does cause problems, but it shows up as a failure to establish TLS with the CA rather than as a nonce error.
Wildcards can only be validated over DNS, so an HTTP challenge that works for every other name will never work for one. If DNS validation is already in use, check the CAA record, though not for the reason usually given: under RFC 8659 an issue record covers wildcards on its own. What blocks a wildcard is an issuewild record naming someone else, because when one is present it takes precedence over issue for wildcard requests.
By where the message came from. A URN such as connection or unauthorized was returned by the CA, so the CA reached your client fine and failed on the way to your web server. A timeout or connection refused printed by the client itself, with no URN, means the client never got that far. The two need opposite fixes: inbound reachability in the first case, outbound in the second.
Yes, whenever you are setting something up for the first time or debugging repeated failures. Certificates from a staging endpoint are not publicly trusted, which is the point: they let you exercise the whole path without consuming production rate limits. Remember that accounts do not carry across, so you register separately against staging and against production.
For more on the protocol behind these errors, see what the ACME protocol is and our ACME SSL certificates page. To check what a live server is serving once issuance succeeds, use the SSL Checker.
Save 10% on SSL Certificates when ordering from SSL Dragon today!
Fast issuance, strong encryption, 99.99% browser trust, dedicated support, and 25-day money-back guarantee. Coupon code: SAVE10

