quarkusio/quarkus · error · IllegalStateException
The certificate to roles mapper is already configured with…
Error message
The certificate to roles mapper is already configured with the 'certificateToRolesMapper' method
What it means
MTLS.Builder supports two mutually exclusive ways to map client certificates to SecurityIdentity roles: attribute-based role mapping via rolesMapping/certificateAttribute, or a custom function via certificateToRolesMapper. This IllegalStateException is thrown from assertCertificateToRolesMapperNotSetYet when a builder already had the custom mapper set and you then attempt to configure the attribute/roles-mapping path. Only one strategy may be configured per builder.
Solutions
- Pick one strategy: remove the certificateToRolesMapper(...) call if you want attribute-based rolesMapping/certificateAttribute
- Or remove the rolesMapping/certificateAttribute call and keep only the custom certificateToRolesMapper function
- If both behaviors are needed, implement the attribute-based logic inside the single certificateToRolesMapper function
Example fix
// before
mtls.certificateToRolesMapper(cert -> Set.of("admin"))
.certificateAttribute("CN"); // IllegalStateException
// after
mtls.certificateToRolesMapper(cert -> {
String cn = ...; // fold attribute logic into the mapper
return Set.of("admin");
}); Defensive patterns
Strategy: validation
Validate before calling
if (builderMapperSet && wantAttributeMapping) { throw new IllegalArgumentException("choose either certificateToRolesMapper or rolesMapping, not both"); } Try / catch
try { mtls.certificateAttribute("CN"); } catch (IllegalStateException e) { log.warn("Mapper already configured; keeping certificateToRolesMapper"); } Prevention
- Configure mTLS role mapping in exactly one place in your security setup
- Search your HttpSecurity builder chain for both mapping methods before adding a new one
- Centralize mTLS builder construction in a single producer/CDI method
When it happens
Trigger: Calling MTLS.Builder.certificateAttribute(...) or rolesMapping(...) after certificateToRolesMapper(Function<X509Certificate, Set<String>>) has already been invoked on the same Builder instance.
Common situations: Programmatically building HttpSecurity with mTLS auth where code paths merge — e.g. default configuration sets a custom mapper and then an extension or user code adds rolesMapping; copy-pasted builder chains that configure both mechanisms.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- The certificate to roles mapper is already configured with…
- TLS configuration is already set
- TLS configuration name has already been configured with the…
- Access token does not contain a confirmation 'cnf' claim…
- Already closed
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/92a7dcac41a645f0.
Report an issue: GitHub.
Appendix: source
Thrown at extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/security/MTLS.java:259
if (roles == null || roles.isEmpty()) {
throw new IllegalArgumentException("Roles cannot be null or empty");
}
assertCertificateToRolesMapperNotSetYet();
if (certificateAttributeValueToRoles == null) {
certificateAttributeValueToRoles = new HashMap<>();
}
certificateAttributeValueToRoles.computeIfAbsent(certificateAttributeValue, new Function<String, Set<String>>() {
@Override
public Set<String> apply(String ignored) {
return new HashSet<>();
}
}).addAll(roles);
return this;
}
private void assertCertificateToRolesMapperNotSetYet() {
if (certificateToRolesMapper != null) {
throw new IllegalStateException(
"The certificate to roles mapper is already configured with the 'certificateToRolesMapper' method");
}
}
/**
* Check the values of different client certificate attributes and map them to the {@link SecurityIdentity} roles.
*
* @param certificateToRolesMapper a client certificate to the {@link SecurityIdentity} roles mapper
* @return Builder
*/
public Builder certificateToRolesMapper(Function<X509Certificate, Set<String>> certificateToRolesMapper) {
if (certificateAttributeValueToRoles != null) {
throw new IllegalStateException(
"The certificate to roles mapper is already configured with the 'rolesMapping' method");
}
assertCertificateToRolesMapperNotSetYet();
this.certificateToRolesMapper = certificateToRolesMapper;
return this;View on GitHub (pinned to e1c734241f)