apereo/cas · warning

Grouper WS did not respond successfully. Ensure your…

Error message

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.

What it means

This is a warning logged by DefaultGrouperFacade.getGroupsForSubjectId when the Grouper Web Service call (WsGetGroupsRequest) throws any exception. CAS could not retrieve groups for the subject from the Grouper WS endpoint, so it returns an empty list instead of the group set. The catch-all means any failure — connectivity, authentication, bad subject id, malformed response — surfaces as this single message.

Solutions

  1. Verify the Grouper WS URL endpoint and credentials in the CAS grouper configuration properties and test them with curl against the WS endpoint.
  2. Confirm the subject id exists in Grouper by querying the WS directly (WsGetSubjects / getGroups) for that subject.
  3. Read the attached exception `e` in the same log line — it identifies the real cause (connectivity vs auth vs parse).
  4. Check network reachability (DNS, firewall, TLS trust store) from the CAS host to the Grouper WS server.

Example fix

// before
cas.authn.grouper.url=https://grouper.example.edu/grouper-ws/servicesRest
// after
cas.authn.grouper.url=https://grouper.example.edu:443/grouper-ws/v2_5_000/servicesRest
// and verify with:
// curl -u wsUser:wsPass -X POST https://grouper.example.edu/grouper-ws/v2_5_000/servicesRest/v2_5_000/groups
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check config and reachability before calling the facade
val wsUrl = casProperties.getAuthn().getGrouper().getWsUrl();
Assert.hasText(wsUrl, "Grouper WS URL must be configured");
var conn = new URL(wsUrl).openConnection();
conn.setConnectTimeout(3000);
conn.connect(); // throws earlier with a clearer error if endpoint unreachable

Try / catch

try {
    var groups = facade.getGroupsForSubjectId(subjectId);
    if (groups.isEmpty()) {
        // degrade gracefully: no groups != fatal
        logger.warn("Grouper returned no groups for {}; continuing with defaults", subjectId);
    }
} catch (Exception e) {
    logger.error("Grouper WS unreachable for subject {}", subjectId, e);
}

Prevention

When it happens

Trigger: Calling getGroupsForSubjectId(subjectId) when: the Grouper WS URL is wrong or unreachable, the configured WS credentials (user/password) are rejected, the subject id does not exist in the Grouper subject source, or the WS client throws while parsing the response (e.g. WsGetGroupsResult unavailable).

Common situations: cas.authn.grouper / GrouperGroupField configuration pointing to a wrong host or port; Grouper WS credentials rotated without updating CAS; LDAP/subject source ids mismatched so the subject lookup fails; network/firewall blocking the WS endpoint; TLS certificate issues against the Grouper server.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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

Appendix: source

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

 *
 * @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) {
        val gcGetPermissionAssignments = new GcGetPermissionAssignments();
        FunctionUtils.doIfNotBlank(query.getAttributeDefinitionName(), gcGetPermissionAssignments::addAttributeDefName);
        FunctionUtils.doIfNotBlank(query.getRoleName(), gcGetPermissionAssignments::addAttributeDefName);
        FunctionUtils.doIfNotBlank(query.getRoleUuid(), gcGetPermissionAssignments::addRoleUuid);
        FunctionUtils.doIfNotBlank(query.getSubjectAttributeName(), gcGetPermissionAssignments::addSubjectAttributeName);

View on GitHub (pinned to e7288fc434)