apereo/cas · warning

Service definition [ ] is undefined or it's not an OpenId…

Error message

Service definition [{}] is undefined or it's not an OpenId Connect relying party

What it means

PairwiseOidcRegisteredServiceUsernameAttributeProvider.resolveUsernameInternal checks that the registered service is an OidcRegisteredService before generating a pairwise subject identifier. If the service is null or of another type, it logs this warning and falls back to the raw principal id, meaning pairwise (per-sector persistent) subject behavior is silently not applied.

Solutions

  1. Make sure the service is registered as an OidcRegisteredService (correct @class in the service JSON).
  2. Remove the pairwise username provider from non-OIDC services; use a suitable provider instead.
  3. Verify the service registry entry loads correctly (service id/name) so context.getRegisteredService() is not null.

Example fix

// before
"@class": "org.apereo.cas.services.RegisteredServiceImpl"
// after
"@class": "org.apereo.cas.services.OidcRegisteredService"
Defensive patterns

Strategy: type-guard

Validate before calling

if (registeredService == null || !(registeredService instanceof OidcRegisteredService)) {
    throw new IllegalArgumentException("Pairwise provider requires an OidcRegisteredService");
}

Type guard

boolean isOidcService(RegisteredService svc) {
    return svc instanceof OidcRegisteredService;
}

Prevention

When it happens

Trigger: Assigning the pairwise username attribute provider to a non-OIDC registered service (e.g. a plain OAuth or CAS service), or resolving the username during processing where the service definition failed to load (null context.getRegisteredService()).

Common situations: Copy-pasting a username attribute provider configuration between service types; service registry returning a generic RegisteredService; misconfigured service JSON missing @class OidcRegisteredService.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at support/cas-server-support-oidc-services/src/main/java/org/apereo/cas/services/PairwiseOidcRegisteredServiceUsernameAttributeProvider.java:53

 * @author Misagh Moayyed
 * @since 5.2.0
 */
@Slf4j
@Getter
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Setter
public class PairwiseOidcRegisteredServiceUsernameAttributeProvider extends BaseRegisteredServiceUsernameAttributeProvider {

    @Serial
    private static final long serialVersionUID = 469929103943101717L;

    private PersistentIdGenerator persistentIdGenerator = new OidcPairwisePersistentIdGenerator();

    @Override
    public String resolveUsernameInternal(final RegisteredServiceUsernameProviderContext context) {
        if (context.getRegisteredService() == null || !OidcRegisteredService.class.isAssignableFrom(context.getRegisteredService().getClass())) {
            LOGGER.warn("Service definition [{}] is undefined or it's not an OpenId Connect relying party", context.getRegisteredService());
            return context.getPrincipal().getId();
        }
        val oidcSvc = (OidcRegisteredService) context.getRegisteredService();
        if (StringUtils.isBlank(oidcSvc.getSubjectType())
            || Strings.CI.equals(OidcSubjectTypes.PUBLIC.getType(), oidcSvc.getSubjectType())) {
            LOGGER.warn("Service definition [{}] does not request a pairwise subject type", oidcSvc);
            return context.getPrincipal().getId();
        }
        val sectorIdentifier = getSectorIdentifier(oidcSvc);
        val id = this.persistentIdGenerator.generate(context.getPrincipal(), sectorIdentifier);
        LOGGER.debug("Resolved username [{}] for pairwise access", id);
        return id;
    }

    private static @Nullable String getSectorIdentifier(final OidcRegisteredService client) {
        if (StringUtils.isNotBlank(client.getSectorIdentifierUri())) {
            val uri = UriComponentsBuilder.fromUriString(client.getSectorIdentifierUri()).build();
            return uri.getHost();

View on GitHub (pinned to e7288fc434)