apereo/cas · error
No groups could be found for
Error message
No groups could be found for [{}] What it means
GrouperRegisteredServiceAccessStrategy.authorizeRequest denies access when the Grouper WS group lookup for the principal returns an empty result set. It logs 'No groups could be found for [principalId]' and returns false, blocking the service request. Note this treats an empty list as deny — it cannot distinguish 'user in no groups' from 'lookup failed'.
Solutions
- Verify the principal id format matches the Grouper subject identifier (check subject source and searchSubject attribute).
- Test the same subject id against the Grouper WS directly to confirm whether memberships exist.
- If users legitimately have no groups, adjust the access strategy (required attributes/groups) to not require Grouper membership.
- Check upstream logs for the Grouper WS warning (error 480) to rule out a connectivity/credential failure masquerading as empty results.
Example fix
// before
val accessStrategy = new GrouperRegisteredServiceAccessStrategy("uid={0}");
// after — ensure the principal attribute used matches the Grouper subject id
val accessStrategy = new GrouperRegisteredServiceAccessStrategy("employeeNumber"); Defensive patterns
Strategy: validation
Validate before calling
// Before relying on the access strategy, confirm the subject resolves in Grouper
var results = facade.fetchGroupsFor(principalId);
if (results == null || results.length == 0) {
logger.warn("Principal {} not resolvable in Grouper; access strategy will deny", principalId);
} Prevention
- Align the principal-id source attribute with the Grouper subject identifier (test with a real user).
- Decide explicitly whether empty Grouper results should mean deny; document it in the service config.
- Monitor for this warning in logs — it also fires during WS outages, not just genuine non-membership.
- Seed test users into Grouper groups in CI to catch id-format mismatches early.
When it happens
Trigger: authorizeRequest (via executeStrategy) when fetchWsGetGroupsResults(request.getPrincipalId()) returns an empty list — i.e. Grouper returned no WsGetGroupsResult for that principal, which happens if the principal id is unknown to Grouper or the upstream WS lookup failed silently.
Common situations: User authenticated via a different id format than the one stored in Grouper (e.g. email vs username); Grouper WS misconfigured so all lookups return empty; user genuinely has no group memberships but the access strategy requires group membership; Grouper WS outage producing empty results.
Understand the failure class
Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.
Related errors
- Subject id [ ] could not be located.
- Denied
- Cannot authorize principal
- Unauthorized account removal attempt
- Unable to login from this location
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/fce5027dd9114d9a.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-grouper-core/src/main/java/org/apereo/cas/grouper/services/GrouperRegisteredServiceAccessStrategy.java:59
private GrouperGroupField groupField = GrouperGroupField.NAME;
/**
* Collection of required attributes
* for this service to proceed.
*/
@JsonSetter(nulls = Nulls.AS_EMPTY)
private Map<String, Set<String>> requiredAttributes = new HashMap<>();
@JsonSetter(nulls = Nulls.AS_EMPTY)
private Map<String, String> configProperties = new TreeMap<>();
@Override
public boolean authorizeRequest(final RegisteredServiceAccessStrategyRequest request) {
val allAttributes = new HashMap<>(request.getAttributes());
val results = fetchWsGetGroupsResults(request.getPrincipalId());
if (results.isEmpty()) {
LOGGER.warn("No groups could be found for [{}]", request.getPrincipalId());
return false;
}
val grouperGroups = new ArrayList<>(results.size());
results
.stream()
.filter(groupsResult -> groupsResult.getWsGroups() != null && groupsResult.getWsGroups().length > 0)
.map(wsGetGroupsResult -> Arrays.stream(wsGetGroupsResult.getWsGroups()).collect(Collectors.toList()))
.flatMap(List::stream)
.forEach(group -> grouperGroups.add(GrouperFacade.getGrouperGroupAttribute(this.groupField, group)));
LOGGER.debug("Adding [{}] under attribute name [{}] to collection of attributes", grouperGroups, GROUPER_GROUPS_ATTRIBUTE_NAME);
allAttributes.put(GROUPER_GROUPS_ATTRIBUTE_NAME, grouperGroups);
return RegisteredServiceAccessStrategyEvaluator.builder()
.requiredAttributes(this.requiredAttributes)
.build()
.apply(request.withAttributes(allAttributes));
}
View on GitHub (pinned to e7288fc434)