apereo/cas · warning

Cannot find entity [ ] in metadata provider for criteria [ ]

Error message

Cannot find entity [{}] in metadata provider for criteria [{}]

What it means

During SAML IdP metadata resolution, the chaining metadata resolver was queried with a criteria set for a specific entityID, but resolveSingle() returned null — no EntityDescriptor for that entity exists in the configured metadata provider(s). The adaptor logs a warning and returns Optional.empty() rather than throwing, because the metadata aggregate loaded fine but simply does not contain that SP's entity ID.

Solutions

  1. Compare the entityID on the CAS registered service with the entityID in the metadata document at the configured metadataLocation (grep for <EntityDescriptor entityID=...>).
  2. Re-download/refresh the metadata source (URL may serve an outdated aggregate) and clear the metadata resolver cache so CAS reloads it.
  3. Verify the metadataLocation (file/URL/HTTP/Classpath resource) on the SamlRegisteredService points to the intended provider.
  4. If the SP intentionally changed entity IDs, update the SP metadata and the CAS service entityID together.
  5. Enable debug logging for org.apereo.cas.support.saml to see which metadata chain was resolved and confirm the expected entity is absent.

Example fix

// before (service config)
// entityId: https://sp.example.org/sso/old
// after
// entityId: https://sp.example.org/saml/sp (matches <EntityDescriptor entityID="https://sp.example.org/saml/sp"> in metadata)
Defensive patterns

Strategy: validation

Validate before calling

// Before registering the service, verify the entity exists in the metadata source
var resolver = SamlMetadataResolverUtils.getMetadataResolverForRegisteredService(casProperties, samlIdPMetadataResolver, registeredService);
var found = resolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(service.getEntityId())));
if (found == null) {
    throw new IllegalStateException("Metadata at " + service.getMetadataLocation()
        + " does not contain entity " + service.getEntityId());
}

Type guard

boolean metadataContainsEntity(EntityDescriptor descriptor, String entityID) {
    return descriptor != null && entityID != null && entityID.equals(descriptor.getEntityID());
}

Try / catch

return metadataResolver.get(service, entityID)
    .map(adaptor -> process(adaptor))
    .orElseGet(() -> {
        log.warn("No metadata for entity {} — check entityID and metadataLocation", entityID);
        return fallbackResponse();
    });

Prevention

When it happens

Trigger: Calling SamlRegisteredServiceMetadataAdaptor.get(entityID, ...) (via SamlRegisteredServiceCachingMetadataResolver.get) where the criteria set (entity ID, RolesDescriptor, SPSSODescriptor) matches no entity in the metadata loaded from registeredService.getMetadataLocation().

Common situations: Wrong entityID configured on the CAS SAML service vs. what the SP published in its metadata; stale/aggregate metadata file or URL that no longer contains the SP; typo or case mismatch in entityID; metadata location points to an aggregate missing this SP; SP changed its entityID after a software upgrade.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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

Appendix: source

Thrown at support/cas-server-support-saml-idp-core/src/main/java/org/apereo/cas/support/saml/services/idp/metadata/SamlRegisteredServiceMetadataAdaptor.java:108

        final SamlRegisteredServiceCachingMetadataResolver resolver,
        final SamlRegisteredService registeredService,
        final String entityID,
        final CriteriaSet criteriaSet) {
        try {
            LOGGER.trace("Adapting SAML metadata for CAS service [{}] issued by [{}]", registeredService.getName(), entityID);
            criteriaSet.add(new EntityIdCriterion(entityID), true);
            LOGGER.debug("Locating metadata for entityID [{}] by attempting to run through the metadata chain...", entityID);
            val cachedResult = Objects.requireNonNull(resolver.resolve(registeredService, criteriaSet),
                () -> "Metadata resolution resulted in a null metadata resolver entry for entity id %s".formatted(entityID));
            
            Assert.isTrue(cachedResult.isResolved(), "Metadata resolution resulted in an unknown metadata resolver entry for entity id %s".formatted(entityID));
            val cachedMetadataResolver = cachedResult.getMetadataResolver();
            LOGGER.debug("Resolved metadata chain from [{}] using [{}]. Filtering the chain by entity ID [{}]",
                registeredService.getMetadataLocation(), cachedMetadataResolver.getId(), entityID);

            val entityDescriptor = cachedMetadataResolver.resolveSingle(criteriaSet);
            if (entityDescriptor == null) {
                LOGGER.warn("Cannot find entity [{}] in metadata provider for criteria [{}]", entityID, criteriaSet);
                return Optional.empty();
            }
            LOGGER.trace("Located entity descriptor in metadata for [{}]", entityID);

            if (entityDescriptor.getValidUntil() != null) {
                val expired = entityDescriptor.getValidUntil()
                    .isBefore(ZonedDateTime.now(ZoneOffset.UTC).toInstant());
                if (expired) {
                    LOGGER.warn("Entity descriptor in the metadata has expired at [{}]", entityDescriptor.getValidUntil());
                    return Optional.empty();
                }
            }
            return getAdaptor(entityID, cachedMetadataResolver, entityDescriptor);
        } catch (final Exception e) {
            LoggingUtils.error(LOGGER, e);
        }
        return Optional.empty();
    }

View on GitHub (pinned to e7288fc434)