quarkusio/quarkus · error · ConfigurationException
Cannot use Let's Encrypt without the quarkus-vertx-http exte
Error message
Cannot use Let's Encrypt without the quarkus-vertx-http extension
What it means
During build, CertificatesProcessor.createManagementRoutes() wires an HTTP route for the ACME challenge. Let's Encrypt renewal requires serving HTTP-01 challenge responses, which is done through Vert.x Web's Router. If io.vertx.ext.web.Router is not present at runtime in the Quarkus classloader, the build fails with this ConfigurationException because the challenge route cannot be registered.
Source
Thrown at extensions/tls-registry/deployment/src/main/java/io/quarkus/tls/deployment/CertificatesProcessor.java:89
.supplier(supplier)
.scope(Singleton.class)
.unremovable()
.setRuntimeInit();
syntheticBeans.produce(configurator.done());
return new TlsRegistryBuildItem(supplier);
}
@Record(ExecutionTime.RUNTIME_INIT)
@BuildStep(onlyIf = LetsEncryptEnabled.class)
void createManagementRoutes(BuildProducer<RouteBuildItem> routes,
LetsEncryptRecorder recorder,
TlsRegistryBuildItem registryBuildItem) {
// Check if Vert.x Web is present
if (!QuarkusClassLoader.isClassPresentAtRuntime("io.vertx.ext.web.Router")) {
throw new ConfigurationException("Cannot use Let's Encrypt without the quarkus-vertx-http extension");
}
recorder.initialize(registryBuildItem.registry());
// Route to handle the Let's Encrypt challenge - primary HTTP server
routes.produce(RouteBuildItem.newAbsoluteRoute("/.well-known/acme-challenge/:token")
.withRequestHandler(recorder.challengeHandler())
.build());
// Route to configure the Let's Encrypt challenge - management server
routes.produce(RouteBuildItem.newManagementRoute("lets-encrypt/challenge")
.withRequestHandler(recorder.chalengeAdminHandler())
.withRouteCustomizer(recorder.setupCustomizer())
.build());
// Route to refresh the certificates - management server
routes.produce(RouteBuildItem.newManagementRoute("lets-encrypt/certs")
.withRequestHandler(recorder.reload())View on GitHub (pinned to e1c734241f)
Solutions
- Add the quarkus-vertx-http extension: ./mvnw quarkus:add-extension -Dextensions="vertx-http"
- If HTTP serving is impossible, disable Let's Encrypt management and provide the certificate out-of-band (quarkus.tls.*.key-store files)
- Remove the Let's Encrypt/ACME config block if the app genuinely never terminates HTTP
- Verify the dependency is in the runtime module, not only deployment, then rebuild
Example fix
// before (pom.xml) <dependency><groupId>io.quarkus</groupId><artifactId>quarkus-tls-registry</artifactId></dependency> // after <dependency><groupId>io.quarkus</groupId><artifactId>quarkus-tls-registry</artifactId></dependency> <dependency><groupId>io.quarkus</groupId><artifactId>quarkus-vertx-http</artifactId></dependency>
Defensive patterns
Strategy: validation
Validate before calling
// build-time guard: ensure vertx-http is on the classpath before enabling ACME
boolean hasVertxHttp = QuarkusClassLoader.isClassPresentAtRuntime("io.vertx.ext.web.Router");
boolean acmeEnabled = config.getOptionalValue("quarkus.tls.*.issuer-reference.acme.enabled", Boolean.class).orElse(false);
if (acmeEnabled && !hasVertxHttp) throw new IllegalStateException("Add the quarkus-vertx-http extension to use Let's Encrypt"); Type guard
boolean letsEncryptUsable() {
return QuarkusClassLoader.isClassPresentAtRuntime("io.vertx.ext.web.Router");
} Try / catch
// build-step failure cannot be caught at runtime; guard the build input
try {
build();
} catch (ConfigurationException e) {
if (e.getMessage().contains("quarkus-vertx-http")) {
throw new IllegalStateException("Add quarkus-vertx-http or disable Let's Encrypt config", e);
}
throw e;
} Prevention
- Add quarkus-vertx-http whenever quarkus-tls-registry with Let's Encrypt is used
- Grep application.properties for lets-contact/acme entries before removing vertx-http
- In extension templates, declare a runtime dependency so the build fails with a clear message early
- Keep ACME config only in apps that serve HTTP (REST/gRPC over HTTP) workloads
When it happens
Trigger: An application enables Let's Encrypt certificate management (quarkus.tls.lets-contact/acme configuration) but does not include the quarkus-vertx-http ( Vert.x HTTP ) extension as a dependency, so QuarkusClassLoader.isClassPresentAtRuntime("io.vertx.ext.web.Router") is false at build time.
Common situations: A non-HTTP (e.g. gRPC-only, or plain TLS without vertx-http) Quarkus app adding TLS registry Let's Encrypt config; removing quarkus-vertx-http during a cleanup and forgetting the ACME config remains; copy-pasting TLS config from a REST app into a background worker.
Related errors
- Invalid configuration: quarkus.http.static-dir.path must poi
- The configuration ${clazz} is missing the @ConfigRoot annota
- Unsupported value: ${value}
- Invalid configuration value set for 'quarkus.arc.remove-unus
- Unknown cache type:
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/e40b2c1b8c16c5cd.
Report an issue: GitHub.