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 supported

View on GitHub (pinned to e1c734241f)

Solutions

  1. Verify you are not requesting a wildcard domain — switch to DNS-01 validation for wildcards or use a concrete subdomain
  2. Check the ACME server configuration/profile to ensure the http-01 challenge type is enabled
  3. Inspect the order's authorization challenges (log challenge types) to confirm what the CA actually offers
  4. 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

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

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/1c33b0491e0da817. Report an issue: GitHub.