{"record":{"id":"92a7dcac41a645f0","repo":"quarkusio/quarkus","slug":"the-certificate-to-roles-mapper-is-already-configu","errorCode":null,"errorMessage":"The certificate to roles mapper is already configured with the 'certificateToRolesMapper' method","messagePattern":"The certificate to roles mapper is already configured with the 'certificateToRolesMapper' method","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/security/MTLS.java","lineNumber":259,"sourceCode":"            if (roles == null || roles.isEmpty()) {\n                throw new IllegalArgumentException(\"Roles cannot be null or empty\");\n            }\n            assertCertificateToRolesMapperNotSetYet();\n            if (certificateAttributeValueToRoles == null) {\n                certificateAttributeValueToRoles = new HashMap<>();\n            }\n            certificateAttributeValueToRoles.computeIfAbsent(certificateAttributeValue, new Function<String, Set<String>>() {\n                @Override\n                public Set<String> apply(String ignored) {\n                    return new HashSet<>();\n                }\n            }).addAll(roles);\n            return this;\n        }\n\n        private void assertCertificateToRolesMapperNotSetYet() {\n            if (certificateToRolesMapper != null) {\n                throw new IllegalStateException(\n                        \"The certificate to roles mapper is already configured with the 'certificateToRolesMapper' method\");\n            }\n        }\n\n        /**\n         * Check the values of different client certificate attributes and map them to the {@link SecurityIdentity} roles.\n         *\n         * @param certificateToRolesMapper a client certificate to the {@link SecurityIdentity} roles mapper\n         * @return Builder\n         */\n        public Builder certificateToRolesMapper(Function<X509Certificate, Set<String>> certificateToRolesMapper) {\n            if (certificateAttributeValueToRoles != null) {\n                throw new IllegalStateException(\n                        \"The certificate to roles mapper is already configured with the 'rolesMapping' method\");\n            }\n            assertCertificateToRolesMapperNotSetYet();\n            this.certificateToRolesMapper = certificateToRolesMapper;\n            return this;","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/security/MTLS.java#L241-L277","documentation":"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.","triggerScenarios":"Calling MTLS.Builder.certificateAttribute(...) or rolesMapping(...) after certificateToRolesMapper(Function<X509Certificate, Set<String>>) has already been invoked on the same Builder instance.","commonSituations":"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.","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"],"exampleFix":"// before\nmtls.certificateToRolesMapper(cert -> Set.of(\"admin\"))\n    .certificateAttribute(\"CN\"); // IllegalStateException\n// after\nmtls.certificateToRolesMapper(cert -> {\n    String cn = ...; // fold attribute logic into the mapper\n    return Set.of(\"admin\");\n});","handlingStrategy":"validation","validationCode":"if (builderMapperSet && wantAttributeMapping) { throw new IllegalArgumentException(\"choose either certificateToRolesMapper or rolesMapping, not both\"); }","typeGuard":null,"tryCatchPattern":"try { mtls.certificateAttribute(\"CN\"); } catch (IllegalStateException e) { log.warn(\"Mapper already configured; keeping certificateToRolesMapper\"); }","preventionTips":["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"],"tags":["mtls","security","illegal-state","builder-misuse"],"backgroundTag":"builder-conflicting-configuration","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}