apereo/cas · warning
Unable to determine duration for SAML service
Error message
Unable to determine duration for SAML service [{}] with no entity id What it means
This is a WARN log, not a thrown error, from SamlRegisteredServiceMetadataExpirationPolicy.getCacheDurationForServiceProvider when the SamlRegisteredService has a blank serviceId (entity ID), making it impossible to resolve an SPSSODescriptor and compute a cache duration. The method returns -1 so the caller falls back to a default duration. It signals a service configuration problem rather than a runtime fault.
Solutions
- Set the entityId/serviceId on the SamlRegisteredService (e.g. via the services management UI or service registry JSON) and save.
- Audit service registry entries for blank entityId values and repair them.
- Fix the import/provisioning pipeline that created the incomplete service record.
- If the -1 fallback duration is unacceptable, correct the data before the policy computes durations; no code change is needed once serviceId is set.
Example fix
// before: services/sp-1001.json missing entityId
{
"@class": "org.apereo.cas.support.saml.services.SamlRegisteredService",
"name": "SP"
}
// after
{
"@class": "org.apereo.cas.support.saml.services.SamlRegisteredService",
"name": "SP",
"serviceId": "https://sp.example.org/metadata"
} Defensive patterns
Strategy: validation
Validate before calling
// Ensure the service has a usable entity id before computing durations
if (service == null || org.apache.commons.lang3.StringUtils.isBlank(service.getServiceId())) {
throw new IllegalArgumentException("SamlRegisteredService requires a non-blank serviceId/entityId");
} Prevention
- Always populate entityId when creating SamlRegisteredService entries
- Run a service-registry audit that flags records with blank serviceId
- Add schema validation to service registry import pipelines
- Treat '-1 duration' warnings as data-quality signals, not normal operation
When it happens
Trigger: duration()/getCacheDurationForServiceProvider invoked for a service whose getServiceId() is blank or whitespace-only, typically a partially constructed SamlRegisteredService or one loaded from a registry entry missing the entityId field.
Common situations: Service registry JSON/YAML entry missing the entityId/serviceId property; programmatic service registration that never set the entity ID; metadata-driven provisioning that produced an empty entity id after a bad import.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- Configuration element indicated an entityCertificate, but…
- Unable to determine entity id to fetch metadata via MDQ for
- Unable to resolve SP ACS URL for AuthnRequest construction
- SAML2 attribute query profile is not enabled
- Skipped registration of
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/49567324faf880b5.
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/SamlRegisteredServiceMetadataExpirationPolicy.java:78
final long currentTime, final long currentDuration) {
LOGGER.trace("Cache expiration duration after updates is set to [{}] nanoseconds", currentDuration);
return currentDuration;
}
@Override
public long expireAfterRead(
final @NonNull SamlRegisteredServiceCacheKey cacheKey,
final @NonNull CachedMetadataResolverResult cacheResult,
final long currentTime, final long currentDuration) {
LOGGER.trace("Cache expiration duration after reads is set to [{}] nanoseconds", currentDuration);
return currentDuration;
}
long getCacheDurationForServiceProvider(final SamlRegisteredService service,
final CachedMetadataResolverResult cacheResult) {
try {
if (StringUtils.isBlank(service.getServiceId())) {
LOGGER.warn("Unable to determine duration for SAML service [{}] with no entity id", service.getName());
return -1;
}
val set = new CriteriaSet();
set.add(new EntityIdCriterion(service.getServiceId()));
set.add(new EntityRoleCriterion(SPSSODescriptor.DEFAULT_ELEMENT_NAME));
val entitySp = cacheResult.getMetadataResolver().resolveSingle(set);
if (entitySp != null && entitySp.getCacheDuration() != null) {
LOGGER.debug("Located cache duration [{}] specified in SP metadata for [{}]", entitySp.getCacheDuration(), entitySp.getEntityID());
return TimeUnit.MILLISECONDS.toNanos(entitySp.getCacheDuration().toMillis());
}
set.clear();
set.add(new EntityIdCriterion(service.getServiceId()));
val entity = cacheResult.getMetadataResolver().resolveSingle(set);
if (entity != null && entity.getCacheDuration() != null) {
LOGGER.debug("Located cache duration [{}] specified in entity metadata for [{}]", entity.getCacheDuration(), entity.getEntityID());
return TimeUnit.MILLISECONDS.toNanos(entity.getCacheDuration().toMillis());
}View on GitHub (pinned to e7288fc434)