apereo/cas · warning

Subject id [ ] could not be located.

Error message

Subject id [{}] could not be located.

What it means

DefaultGrouperFacade.getGroupsForSubjectId() calls the Grouper web service via fetchGroupsFor(subjectId). If the WS returns null or an empty result array, the subject has no (or unknown) group membership; CAS logs this warning and returns an empty list. Exceptions (bad credentials, unreachable WS) are caught separately and also return an empty list.

Solutions

  1. Verify the subjectId value exists in Grouper and matches the configured subject source (subjectId vs subjectIdentifier)
  2. Check the Grouper WS credentials/URL configured for the facade by querying a known-good subject
  3. Confirm in the Grouper UI that the subject actually belongs to groups (zero groups is a valid empty result)
  4. Inspect the caller's logic: authorization attributes derived from an empty list will deny access

Example fix

// before
grouperFacade.getGroupsForSubjectId(username); // may not resolve
// after (use the identifier Grouper's source resolves)
grouperFacade.getGroupsForSubjectId(user.getAttributeValue("eppn"));
Defensive patterns

Strategy: fallback

Validate before calling

if (subjectId == null || subjectId.isBlank()) {
    throw new IllegalArgumentException("subjectId required");
}

Try / catch

var groups = grouperFacade.getGroupsForSubjectId(subjectId);
if (groups.isEmpty()) {
    LOGGER.debug("no grouper groups for {}; denying by default", subjectId);
}

Prevention

When it happens

Trigger: getGroupsForSubjectId called with a subjectId that does not exist in Grouper, uses the wrong subject source/identifier format (e.g. username vs ePPN vs internal id), or the WS query legitimately matches zero groups.

Common situations: Grouper subject source misconfiguration where CAS passes an identifier Grouper cannot resolve; users with no group assignments; typo'd subjectId passed from calling authorization code.

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


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/43a1f037f2f7f4b9. Report an issue: GitHub.

Appendix: source

Thrown at support/cas-server-support-grouper-core/src/main/java/org/apereo/cas/grouper/DefaultGrouperFacade.java:30

import lombok.val;
import org.apache.commons.lang3.StringUtils;

/**
 * This is {@link DefaultGrouperFacade} that acts as a wrapper
 * in front of the grouper API.
 *
 * @author Misagh Moayyed
 * @since 5.1.0
 */
@Slf4j
public class DefaultGrouperFacade implements GrouperFacade {

    @Override
    public Collection<WsGetGroupsResult> getGroupsForSubjectId(final String subjectId) {
        try {
            val results = fetchGroupsFor(subjectId);
            if (results == null || results.length == 0) {
                LOGGER.warn("Subject id [{}] could not be located.", subjectId);
                return new ArrayList<>();
            }
            LOGGER.debug("Found [{}] groups for [{}]", results.length, subjectId);
            return CollectionUtils.wrapList(results);
        } catch (final Exception e) {
            LOGGER.warn("Grouper WS did not respond successfully. Ensure your credentials are correct "
                + ", the url endpoint for Grouper WS is correctly configured and the subject [{}] exists in Grouper.", subjectId, e);
        }
        return new ArrayList<>();
    }

    protected WsGetGroupsResult[] fetchGroupsFor(final String subjectId) {
        val groupsClient = new GcGetGroups().addSubjectId(subjectId);
        return groupsClient.execute().getResults();
    }

    @Override
    public WsGetPermissionAssignmentsResults getPermissionAssignments(final GrouperPermissionAssignmentsQuery query) {

View on GitHub (pinned to e7288fc434)