apereo/cas · error · SamlException

Unable to get entity from MDQ server and a backup file does…

Error message

Unable to get entity from MDQ server and a backup file does not exist.

What it means

Thrown by the MDQ (Metadata Query Protocol) resolver when the HTTP response from the MDQ server is not a 2xx success AND no backup metadata file exists on disk for the entity. The resolver normally caches fetched metadata to a backup file so it can serve it during outages; without either a live response or a cached copy, metadata resolution cannot proceed.

Solutions

  1. Verify the MDQ server URL and that it responds 200 for the entityID (curl the query URL).
  2. Check network/proxy connectivity from the CAS server to the MDQ server.
  3. If metadata is available from a prior fetch, restore the backup file to the configured location.
  4. Fix the entityID configured on the SAML registered service so MDQ can find the entity.
  5. Configure a reachable MDQ endpoint or switch the service to static metadata.

Example fix

// before
cas.authn.saml.idp.metadata.query-protocol.url=https://wrong-mdq.example.org/idp
// after
cas.authn.saml.idp.metadata.query-protocol.url=https://mdq.example.org/mdq
Defensive patterns

Strategy: fallback

Validate before calling

val queryUrl = mdqBaseUrl + "/entities/" + EncodingUtils.urlEncode(entityId);
if (!Files.exists(backupPath)) {
    try (var conn = new URL(queryUrl).openConnection()) { conn.connect(); }
}

Type guard

boolean hasBackup(File f) { return f != null && Files.exists(f.toPath()); }

Try / catch

try {
    return resolver.resolve(criteriaSet);
} catch (SamlException e) {
    LOGGER.warn("MDQ fetch failed, trying backup metadata", e);
    return loadFromStaticBackup(criteriaSet);
}

Prevention

When it happens

Trigger: Calling resolveFromMetadataQueryProtocolServer (via getMetadataResolverFromResponse) when the MDQ server returns a non-2xx status (404 for unknown entityID, 500, timeout at gateway) and backupFile does not exist on disk (first fetch never succeeded or the file was deleted).

Common situations: MDQ server down or misconfigured URL in cas.authn.saml.idp.metadata.query-protocol.*; wrong entityID requested (404); firewall/proxy blocking outbound HTTP; first-time setup with no cached backup; backup directory wiped or not writable in a container restart.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/e30ee616f95cb936. 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/resolver/MetadataQueryProtocolMetadataResolver.java:65

    public boolean supports(final SamlRegisteredService service) {
        val locations = org.springframework.util.StringUtils.commaDelimitedListToSet(
            SpringExpressionLanguageValueResolver.getInstance().resolve(service.getMetadataLocation())
        );
        return locations.stream().anyMatch(SamlUtils::isDynamicMetadataQueryConfigured);
    }

    @Override
    protected boolean shouldHttpResponseStatusBeProcessed(final HttpStatus status) {
        return true;
    }

    @Override
    protected AbstractMetadataResolver getMetadataResolverFromResponse(final HttpResponse response, final File backupFile) throws Exception {
        if (!HttpStatus.valueOf(response.getCode()).is2xxSuccessful()) {
            if (Files.exists(backupFile.toPath())) {
                return new InMemoryResourceMetadataResolver(backupFile, this.configBean);
            }
            throw new SamlException("Unable to get entity from MDQ server and a backup file does not exist.");
        }
        val entity = ((HttpEntityContainer) response).getEntity();
        val result = IOUtils.toString(entity.getContent(), StandardCharsets.UTF_8);
        val path = backupFile.toPath();
        LOGGER.trace("Writing metadata to file at [{}]", path);
        try (val output = Files.newBufferedWriter(path, StandardCharsets.UTF_8)) {
            IOUtils.write(result, output);
            output.flush();
            StreamSupport.stream(path.getFileSystem().getFileStores().spliterator(), false)
                .filter(store -> store.supportsFileAttributeView(UserDefinedFileAttributeView.class))
                .forEach(store -> setFileAttribute(response, backupFile));
        }
        EntityUtils.consume(entity);
        return new InMemoryResourceMetadataResolver(backupFile, configBean);
    }

    @Override
    protected HttpResponse fetchMetadata(final SamlRegisteredService service,

View on GitHub (pinned to e7288fc434)