quarkusio/quarkus · error · IllegalArgumentException

Target roles for role '%s' must not be null

Error message

Target roles for role '%s' must not be null

What it means

The same single-entry overload rejects a null target-roles list with an IllegalArgumentException formatted with the source role name. Target roles are the replacement/granted roles, so a null list would make the mapping entry unusable. Note that even a non-null list still goes through the Map-based overload, which rejects empty lists.

Source

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

                    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;
    }

    @Override
    public HttpSecurity rolesMapping(String sourceRole, List<String> targetRoles) {
        if (sourceRole == null) {
            throw new IllegalArgumentException("Source role must not be null");
        }
        if (targetRoles == null) {
            throw new IllegalArgumentException("Target roles for role '%s' must not be null".formatted(sourceRole));
        }
        return rolesMapping(Map.of(sourceRole, targetRoles));
    }

    @Override
    public HttpSecurity rolesMapping(String sourceRole, String targetRole) {
        if (targetRole == null) {
            throw new IllegalArgumentException("Target role for role '%s' must not be null".formatted(sourceRole));
        }
        return rolesMapping(sourceRole, List.of(targetRole));
    }

    void addHttpPermissions(List<HttpPermissionCarrier> httpPermissions) {
        this.httpPermissions.addAll(httpPermissions);
    }

    private final class AuthorizationPolicy implements Authorization {

View on GitHub (pinned to e1c734241f)

Solutions

  1. Provide a non-empty List.of(...) of target roles for the mapping.
  2. Skip the rolesMapping call when the configured target list is absent.
  3. Check that the accessor feeding the list returns an empty list rather than null for missing config.

Example fix

// before
httpSecurity.rolesMapping("user", config.targetRoles()); // may be null
// after
List<String> targets = config.targetRoles();
if (targets != null && !targets.isEmpty()) {
    httpSecurity.rolesMapping("user", targets);
}
Defensive patterns

Strategy: validation

Validate before calling

if (targetRoles != null && !targetRoles.isEmpty()) {
    httpSecurity.rolesMapping(sourceRole, targetRoles);
}

Type guard

static boolean hasTargets(List<String> targetRoles) {
    return targetRoles != null && !targetRoles.isEmpty();
}

Try / catch

try {
    httpSecurity.rolesMapping("user", targets);
} catch (IllegalArgumentException e) {
    log.error("Invalid target roles: " + e.getMessage());
}

Prevention

When it happens

Trigger: rolesMapping("user", null); passing a List<String> variable that was never populated; a config accessor returning null for an optional roles list that is then forwarded directly.

Common situations: Programmatic security wiring where target roles come from optional config; mapping an identity-provider role to application roles where the mapping table entry was missing; test scaffolding that forgot to set the list.

Related errors


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