quarkusio/quarkus · error · IllegalStateException

Roles mapping is already configured

Error message

Roles mapping is already configured

What it means

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.

Source

Thrown at extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpSecurityImpl.java:236

    @Override
    public HttpPermission put(String... paths) {
        return path(paths).methods("PUT");
    }

    @Override
    public HttpPermission post(String... paths) {
        return path(paths).methods("POST");
    }

    @Override
    public HttpPermission delete(String... paths) {
        return path(paths).methods("DELETE");
    }

    @Override
    public HttpSecurity rolesMapping(Map<String, List<String>> roleToRoles) {
        if (rolesMapping != null) {
            throw new IllegalStateException("Roles mapping is already configured");
        }
        if (roleToRoles == null || roleToRoles.isEmpty()) {
            throw new IllegalArgumentException("Roles must not be empty");
        }
        roleToRoles.forEach(new BiConsumer<String, List<String>>() {
            @Override
            public void accept(String sourceRole, List<String> targetRoles) {
                if (sourceRole.isEmpty()) {
                    throw new IllegalArgumentException("Source role must not be empty");
                }
                if (targetRoles == null || targetRoles.isEmpty()) {
                    throw new IllegalArgumentException("Target roles for role '%s' must not be empty".formatted(sourceRole));
                }
            }
        });

        this.rolesMapping = RolesMapping.of(roleToRoles);
        return this;

View on GitHub (pinned to e1c734241f)

Solutions

  1. Call rolesMapping only once per HttpSecurity instance; merge all role mappings into a single Map before the call.
  2. Chain carefully: note rolesMapping throws by design when re-entered — remove the second call rather than chaining it again.
  3. If multiple sources provide mappings, combine them into one map first and pass the merged result.

Example fix

// before
httpSecurity.rolesMapping(Map.of("admin", List.of("manager")));
httpSecurity.rolesMapping(Map.of("user", List.of("viewer"))); // throws
// after
Map<String, List<String>> merged = new HashMap<>();
merged.put("admin", List.of("manager"));
merged.put("user", List.of("viewer"));
httpSecurity.rolesMapping(merged);
Defensive patterns

Strategy: validation

Validate before calling

// merge all role mappings into ONE map and call rolesMapping exactly once
Map<String, List<String>> merged = new HashMap<>();
merged.putAll(sourceAMappings);
merged.putAll(sourceBMappings);
httpSecurity.rolesMapping(merged);

Try / catch

try {
    httpSecurity.rolesMapping(mapping);
} catch (IllegalStateException e) {
    if (e.getMessage().contains("Roles mapping is already configured")) {
        log.warn("Roles mapping already applied; merging into existing configuration instead");
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling httpSecurity.rolesMapping(...) twice on the same HttpSecurity instance, or calling it after addAuthRuntimeConfigToHttpSecurity already populated the mapping.

Common situations: 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.

Related errors


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