quarkusio/quarkus · error · IllegalStateException

The certificate to roles mapper is already configured with t

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.

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)

Solutions

  1. Pick one strategy: remove the certificateToRolesMapper(...) call if you want attribute-based rolesMapping/certificateAttribute
  2. Or remove the rolesMapping/certificateAttribute call and keep only the custom certificateToRolesMapper function
  3. 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

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

Related errors


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