apereo/cas · error · SamlException

Unable to locate a valid SAML metadata resolver for to…

Error message

Unable to locate a valid SAML metadata resolver for  to locate 

What it means

SamlRegisteredServiceDefaultCachingMetadataResolver.execute() retries loading a metadata resolver for the cache key and validates each attempt: after obtaining a cached result it checks that the resolver can actually produce valid metadata for the criteria set. If the check fails it invalidates the cache entry (invalidating the service's cached resolver when count==1) and throws SamlException that no valid SAML metadata resolver could be located for the metadata location.

Solutions

  1. Validate the metadata document at metadataLocation directly (xmllint --schema against MDUI/MD schema; check validUntil/signature) and fix or re-fetch it.
  2. Clear/restart the metadata resolver cache or wait for retry exhaustion so the bad entry is invalidated, then reload.
  3. Confirm the metadataLocation is reachable from CAS and returns real SAML metadata, not an HTML error or redirect page.
  4. Increase cas.authn.samlIdp.metadata.core.maximum-retry-attempts only after fixing the underlying metadata validity issue.

Example fix

// before
<saml MD:validUntil="2020-01-01T00:00:00Z" ...>  // expired metadata still cached

// after
# re-fetch fresh metadata into the location and clear cached resolver
rm -rf ${cache-dir}/saml-metadata-resolver/*  # or restart CAS
curl -fsSL https://idp.example.edu/idp/shibboleth -o /etc/cas/saml/idp-metadata.xml
Defensive patterns

Strategy: retry

Validate before calling

// check metadata validity before/at reload
Document md = parse(metadataLocation);
if (md.getValidUntil() != null && md.getValidUntil().isBeforeNow())
    logger.warn("Metadata at {} expired; refresh required", metadataLocation);

Try / catch

try {
    result = cachingResolver.execute(service, criteriaSet);
} catch (SamlException e) {
    logger.warn("Resolver invalid for {}; forcing cache invalidation and reload", metadataLocation);
    cachingResolver.invalidate(service, criteriaSet);
    result = cachingResolver.execute(service, criteriaSet); // single deliberate retry after invalidation
}

Prevention

When it happens

Trigger: execute() (public) runs within the configured maximumRetryAttempts; the CachedMetadataResolverResult is returned but its resolver fails to resolve valid metadata for the given criteriaSet against metadataLocation, triggering invalidate() plus the SamlException.

Common situations: Metadata at the location became invalid/expired while a stale resolver was cached; the metadata document no longer validates (expired validityInterval, bad signature); remote metadata URL now returns an error page; after metadata edits the old cache entry is still in use.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at support/cas-server-support-saml-idp-metadata/src/main/java/org/apereo/cas/support/saml/services/idp/metadata/cache/SamlRegisteredServiceDefaultCachingMetadataResolver.java:90

        val cacheKey = new SamlRegisteredServiceCacheKey(service, criteriaSet);
        return FunctionUtils.doAndRetry(
            new Retryable<>() {
                @Override
                public @Nullable CachedMetadataResolverResult execute() throws Throwable {
                    LOGGER.debug("Locating cached metadata resolver using key [{}] for service [{}].",
                        cacheKey.getId(), service.getName());
                    val queryResult = locateAndCacheMetadataResolver(service, criteriaSet, cacheKey);
                    val result = isMetadataResolverAcceptable(queryResult, criteriaSet);
                    if (!result.isValid()) {
                        val criteria = new EvaluableEntityRoleEntityDescriptorCriterion(SPSSODescriptor.DEFAULT_ELEMENT_NAME);
                        val count = Iterables.size(result.getResult().getMetadataResolver().resolve(new CriteriaSet(criteria)));
                        if (count == 1) {
                            invalidate(service, criteriaSet);
                        }
                        LOGGER.warn("SAML metadata resolver [{}] obtained from the cache is "
                                + "unable to produce/resolve valid metadata from [{}]. Metadata resolver cache entry with key [{}] "
                                + "has been invalidated.", result.getResult().getMetadataResolver().getId(), metadataLocation, cacheKey.getId());
                        throw new SamlException("Unable to locate a valid SAML metadata resolver for "
                            + metadataLocation + " to locate " + criteriaSet);
                    }
                    return queryResult.getResult();
                }
            },
            casProperties.getAuthn().getSamlIdp().getMetadata().getCore().getMaximumRetryAttempts());
    }

    @Override
    public void invalidate() {
        LOGGER.trace("Invalidating cache, removing all metadata resolvers");
        cache.invalidateAll();
    }

    @Override
    public void invalidate(final SamlRegisteredService service, final CriteriaSet criteriaSet) {
        LOGGER.trace("Invalidating cache for [{}].", service.getName());
        val cacheKey = new SamlRegisteredServiceCacheKey(service, criteriaSet);

View on GitHub (pinned to e7288fc434)