apereo/cas · error · IllegalArgumentException

Unable to find supported NameID format for service

Error message

Unable to find supported NameID format for service %s

What it means

When creating the NameID for a SAML single-logout response, SamlIdPProfileSingleLogoutMessageCreator.buildNameId iterates the configured NameID formats and tries to produce a NameID for the service; if every candidate fails or none applies, it throws this IllegalArgumentException. The IdP cannot determine a NameID format supported both by its configuration and the registered SAML service.

Solutions

  1. Add the SP-required format to the service's nameIdFormats in the SamlRegisteredService config
  2. Use a broadly supported format like urn:oasis:names:tc:SAML:2.0:nameid-format:transient if policy allows
  3. If persistent NameID is needed, configure and populate the persistent IdP/SP data store
  4. Check the SP metadata NameIDFormat list and align CAS service configuration with it

Example fix

// before (service registry JSON)
"nameIdFormats": ["urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"]
// after: include a format CAS can resolve without stored pairwise IDs
"nameIdFormats": ["urn:oasis:names:tc:SAML:2.0:nameid-format:transient"]
Defensive patterns

Strategy: validation

Validate before calling

// confirm format intersection before invoking SLO NameID building
Set<String> supported = Set.of("urn:oasis:names:tc:SAML:2.0:nameid-format:transient");
if (spMetadataNameIdFormats.stream().noneMatch(supported::contains)) {
    throw new ConfigurationException("No mutually supported NameID format for " + service.getServiceId());
}

Prevention

When it happens

Trigger: nameId -> buildNameId for a SLO flow when the service's supported NameID formats (or the IdP's configured formats) yield no resolvable NameID — e.g. persistent NameID requested but no matching persistent IdP/SP pair stored, or no format intersection between IdP and SP metadata.

Common situations: SP metadata requests a NameID format CAS is not configured to produce (transient/persistent/emailAddress mismatch); nameIdFormats not set on the SamlRegisteredService so defaults don't match; persistent NameID store (data store) missing the pairwise ID for the user/SP pair.

Related errors


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

Appendix: source

Thrown at support/cas-server-support-saml-idp-web/src/main/java/org/apereo/cas/support/saml/web/idp/profile/slo/SamlIdPProfileSingleLogoutMessageCreator.java:126

        if (effectiveNameIdFormats.isEmpty()) {
            effectiveNameIdFormats.add(NameIDType.UNSPECIFIED);
        }

        for (val nameFormat : effectiveNameIdFormats) {
            try {
                val nameIdValue = buildLogoutRequestNameId(request, nameFormat);
                val encoder = SamlAttributeBasedNameIdGenerator.get(Optional.empty(), nameFormat, samlService, nameIdValue);
                LOGGER.debug("Encoding NameID based on [{}]", nameFormat);
                val nameId = encoder.generate(new ProfileRequestContext(), nameFormat);
                if (nameId != null) {
                    LOGGER.debug("Generated NameID [{}] with format [{}]", nameId.getValue(), nameFormat);
                    return nameId;
                }
            } catch (final Exception e) {
                LoggingUtils.error(LOGGER, e);
            }
        }
        throw new IllegalArgumentException("Unable to find supported NameID format for service %s".formatted(samlService.getServiceId()));
    }

    protected boolean shouldSignLogoutRequestFor(final SamlRegisteredService registeredService) {
        val samlIdPProperties = samlProfileHandlerConfigurationContext.getCasProperties().getAuthn().getSamlIdp();
        return registeredService.getSignLogoutRequest().isUndefined()
            ? samlIdPProperties.getLogout().isForceSignedLogoutRequests()
            : registeredService.getSignLogoutRequest().isTrue();
    }

    protected String buildLogoutRequestNameId(final SingleLogoutRequestContext request, final String nameIdFormat) throws Throwable {
        val samlService = (SamlRegisteredService) request.getRegisteredService();
        LOGGER.debug("Preparing NameID attribute for SAML service [{}] with format [{}]", samlService.getName(), nameIdFormat);
        val principal = request.getExecutionRequest().getTicketGrantingTicket()
            .getAuthentication().getPrincipal();
        if (NameIDType.TRANSIENT.equalsIgnoreCase(StringUtils.trim(nameIdFormat))) {
            val serviceId = request.getService().getId();
            val resolver = samlProfileHandlerConfigurationContext.getSamlRegisteredServiceCachingMetadataResolver();
            val adaptorRes = SamlRegisteredServiceMetadataAdaptor.get(resolver, samlService, serviceId);

View on GitHub (pinned to e7288fc434)