{"record":{"id":"e9acdddf4e789b8b","repo":"quarkusio/quarkus","slug":"roles-mapping-is-already-configured","errorCode":null,"errorMessage":"Roles mapping is already configured","messagePattern":"Roles mapping is already configured","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpSecurityImpl.java","lineNumber":236,"sourceCode":"    @Override\n    public HttpPermission put(String... paths) {\n        return path(paths).methods(\"PUT\");\n    }\n\n    @Override\n    public HttpPermission post(String... paths) {\n        return path(paths).methods(\"POST\");\n    }\n\n    @Override\n    public HttpPermission delete(String... paths) {\n        return path(paths).methods(\"DELETE\");\n    }\n\n    @Override\n    public HttpSecurity rolesMapping(Map<String, List<String>> roleToRoles) {\n        if (rolesMapping != null) {\n            throw new IllegalStateException(\"Roles mapping is already configured\");\n        }\n        if (roleToRoles == null || roleToRoles.isEmpty()) {\n            throw new IllegalArgumentException(\"Roles must not be empty\");\n        }\n        roleToRoles.forEach(new BiConsumer<String, List<String>>() {\n            @Override\n            public void accept(String sourceRole, List<String> targetRoles) {\n                if (sourceRole.isEmpty()) {\n                    throw new IllegalArgumentException(\"Source role must not be empty\");\n                }\n                if (targetRoles == null || targetRoles.isEmpty()) {\n                    throw new IllegalArgumentException(\"Target roles for role '%s' must not be empty\".formatted(sourceRole));\n                }\n            }\n        });\n\n        this.rolesMapping = RolesMapping.of(roleToRoles);\n        return this;","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpSecurityImpl.java#L218-L254","documentation":"Each HttpSecurity instance allows exactly one roles mapping. HttpSecurity.rolesMapping(Map) checks an internal rolesMapping field and throws an IllegalStateException if it was already populated (either by a previous rolesMapping call or by addAuthRuntimeConfigToHttpSecurity). Role-to-roles merging is not supported at this level, so a second attempt fails.","triggerScenarios":"Calling httpSecurity.rolesMapping(...) twice on the same HttpSecurity instance, or calling it after addAuthRuntimeConfigToHttpSecurity already populated the mapping.","commonSituations":"Security setup helpers invoked multiple times (e.g. in different lifecycle phases or dev-mode reload); two libraries/initializers both applying roles mapping to the same builder; chained rolesMapping(...) calls in a fluent setup.","solutions":["Call rolesMapping only once per HttpSecurity instance; merge all role mappings into a single Map before the call.","Chain carefully: note rolesMapping throws by design when re-entered — remove the second call rather than chaining it again.","If multiple sources provide mappings, combine them into one map first and pass the merged result."],"exampleFix":"// before\nhttpSecurity.rolesMapping(Map.of(\"admin\", List.of(\"manager\")));\nhttpSecurity.rolesMapping(Map.of(\"user\", List.of(\"viewer\"))); // throws\n// after\nMap<String, List<String>> merged = new HashMap<>();\nmerged.put(\"admin\", List.of(\"manager\"));\nmerged.put(\"user\", List.of(\"viewer\"));\nhttpSecurity.rolesMapping(merged);","handlingStrategy":"validation","validationCode":"// merge all role mappings into ONE map and call rolesMapping exactly once\nMap<String, List<String>> merged = new HashMap<>();\nmerged.putAll(sourceAMappings);\nmerged.putAll(sourceBMappings);\nhttpSecurity.rolesMapping(merged);","typeGuard":null,"tryCatchPattern":"try {\n    httpSecurity.rolesMapping(mapping);\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"Roles mapping is already configured\")) {\n        log.warn(\"Roles mapping already applied; merging into existing configuration instead\");\n    } else {\n        throw e;\n    }\n}","preventionTips":["Call rolesMapping exactly once per HttpSecurity instance — never chain it.","Consolidate role mappings from all sources into one map before applying.","Watch for setup helpers that can run twice (dev reload, multiple initializers) and make them idempotent."],"tags":["quarkus","http-security","roles-mapping","repeated-initialization"],"backgroundTag":"duplicate-configuration-source","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"}