quarkusio/quarkus · error · RuntimeException
Missing certificate authority challenge
Error message
Missing certificate authority challenge
What it means
During ACME identifier proofing, AcmeClient iterates the challenges offered by the certificate authority for the order and selects the HTTP-01 challenge. If none of the returned challenges is an HTTP-01 type, selectedChallenge stays null and this RuntimeException is thrown. It means the CA did not offer the challenge type this client is prepared to fulfill.
Source
Thrown at extensions/tls-registry/cli/src/main/java/io/quarkus/tls/cli/letsencrypt/AcmeClient.java:153
}
@Override
public AcmeChallenge proveIdentifierControl(AcmeAccount account, List<AcmeChallenge> challenges)
throws AcmeException {
Assert.checkNotNullParam("account", account);
Assert.checkNotNullParam("challenges", challenges);
AcmeChallenge selectedChallenge = null;
for (AcmeChallenge challenge : challenges) {
if (challenge.getType() == AcmeChallenge.Type.HTTP_01) {
AUDIT.info("Selected HTTP-01 challenge for domain validation");
LOGGER.debug("HTTP 01 challenge is selected");
selectedChallenge = challenge;
break;
}
}
if (selectedChallenge == null) {
throw new RuntimeException("Missing certificate authority challenge");
}
// ensure the token is valid before proceeding
String token = selectedChallenge.getToken();
if (!token.matches(TOKEN_REGEX)) {
AUDIT.error("Invalid challenge token format - rejecting");
throw new RuntimeException("Invalid certificate authority challenge");
}
LOGGER.debugf("Preparing a selected challenge content for token %s", token);
String selectedChallengeString = selectedChallenge.getKeyAuthorization(account);
// Check rate limit before uploading challenge
checkRateLimit("challenge-upload");
// respond to the http challenge
if (managementClient != null) {
//TODO: Use JsonObject once POST is supportedView on GitHub (pinned to e1c734241f)
Solutions
- Verify you are not requesting a wildcard domain — switch to DNS-01 validation for wildcards or use a concrete subdomain
- Check the ACME server configuration/profile to ensure the http-01 challenge type is enabled
- Inspect the order's authorization challenges (log challenge types) to confirm what the CA actually offers
- Point the client at the standard Let's Encrypt ACME directory if a non-standard CA was configured
Example fix
// before: wildcard requires dns-01, so no http-01 challenge exists
acmeClient.proveIdentifierControl("*.example.com", ...);
// after: use a concrete hostname for http-01
acmeClient.proveIdentifierControl("app.example.com", ...); Defensive patterns
Strategy: validation
Validate before calling
import sh.acme.*;
static boolean hasHttp01Challenge(Authorization auth) {
return auth != null && auth.getChallenges() != null && auth.getChallenges().stream()
.anyMatch(c -> ChallengeType.HTTP_01.equals(c.getType()));
}
// check before proving: if (!hasHttp01Challenge(order.getAuthorization(domain))) skip/switch to dns-01
Type guard
static boolean isHttp01(Challenge c) {
return c != null && "http-01".equals(c.getType());
}
Try / catch
try {
acmeClient.proveIdentifierControl(identifier, account, ...);
} catch (RuntimeException e) {
if (e.getMessage().equals("Missing certificate authority challenge")) {
// fall back to DNS-01 or fail with a clear message about unsupported challenge type
} else {
throw e;
}
} Prevention
- Avoid wildcard identifiers when using HTTP-01; use DNS-01 for *.domain certificates
- Confirm the target ACME CA profile enables the http-01 challenge type
- Log available challenge types per authorization to detect CA capability issues early
- Test against a CA (Pebble/Let's Encrypt staging) known to offer http-01 before production runs
When it happens
Trigger: Calling proveIdentifierControl when the ACME order's authorizations contain no http-01 challenge — e.g. the CA profile only offers dns-01 or tls-alpn-01, the identifier is a wildcard domain (wildcards require dns-01), or the authorization object structure changed so no challenge matched the selection logic.
Common situations: Requesting a wildcard certificate (*.example.com), which Let's Encrypt only validates via DNS-01; using an ACME directory/CA (e.g. a private Pebble or ZeroSSL profile) that does not enable HTTP-01; an order for an identifier whose authorization already moved to a state without a usable challenge.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Rate limit exceeded: too many ACME challenge requests. Wait
- Failed to respond to certificate authority challenge
- Invalid certificate authority challenge
- Failure to save the account
- Failed to obtain certificate: <reason>
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/1c33b0491e0da817.
Report an issue: GitHub.