{"record":{"id":"49567324faf880b5","repo":"apereo/cas","slug":"unable-to-determine-duration-for-saml-service","errorCode":null,"errorMessage":"Unable to determine duration for SAML service [{}] with no entity id","messagePattern":"Unable to determine duration for SAML service \\[(.+?)\\] with no entity id","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"support/cas-server-support-saml-idp-metadata/src/main/java/org/apereo/cas/support/saml/services/idp/metadata/cache/SamlRegisteredServiceMetadataExpirationPolicy.java","lineNumber":78,"sourceCode":"        final long currentTime, final long currentDuration) {\n        LOGGER.trace(\"Cache expiration duration after updates is set to [{}] nanoseconds\", currentDuration);\n        return currentDuration;\n    }\n\n    @Override\n    public long expireAfterRead(\n        final @NonNull SamlRegisteredServiceCacheKey cacheKey,\n        final @NonNull CachedMetadataResolverResult cacheResult,\n        final long currentTime, final long currentDuration) {\n        LOGGER.trace(\"Cache expiration duration after reads is set to [{}] nanoseconds\", currentDuration);\n        return currentDuration;\n    }\n\n    long getCacheDurationForServiceProvider(final SamlRegisteredService service,\n                                            final CachedMetadataResolverResult cacheResult) {\n        try {\n            if (StringUtils.isBlank(service.getServiceId())) {\n                LOGGER.warn(\"Unable to determine duration for SAML service [{}] with no entity id\", service.getName());\n                return -1;\n            }\n            val set = new CriteriaSet();\n            set.add(new EntityIdCriterion(service.getServiceId()));\n            set.add(new EntityRoleCriterion(SPSSODescriptor.DEFAULT_ELEMENT_NAME));\n            val entitySp = cacheResult.getMetadataResolver().resolveSingle(set);\n            if (entitySp != null && entitySp.getCacheDuration() != null) {\n                LOGGER.debug(\"Located cache duration [{}] specified in SP metadata for [{}]\", entitySp.getCacheDuration(), entitySp.getEntityID());\n                return TimeUnit.MILLISECONDS.toNanos(entitySp.getCacheDuration().toMillis());\n            }\n\n            set.clear();\n            set.add(new EntityIdCriterion(service.getServiceId()));\n            val entity = cacheResult.getMetadataResolver().resolveSingle(set);\n            if (entity != null && entity.getCacheDuration() != null) {\n                LOGGER.debug(\"Located cache duration [{}] specified in entity metadata for [{}]\", entity.getCacheDuration(), entity.getEntityID());\n                return TimeUnit.MILLISECONDS.toNanos(entity.getCacheDuration().toMillis());\n            }","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-saml-idp-metadata/src/main/java/org/apereo/cas/support/saml/services/idp/metadata/cache/SamlRegisteredServiceMetadataExpirationPolicy.java#L60-L96","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: services/sp-1001.json missing entityId\n{\n  \"@class\": \"org.apereo.cas.support.saml.services.SamlRegisteredService\",\n  \"name\": \"SP\"\n}\n// after\n{\n  \"@class\": \"org.apereo.cas.support.saml.services.SamlRegisteredService\",\n  \"name\": \"SP\",\n  \"serviceId\": \"https://sp.example.org/metadata\"\n}","handlingStrategy":"validation","validationCode":"// Ensure the service has a usable entity id before computing durations\nif (service == null || org.apache.commons.lang3.StringUtils.isBlank(service.getServiceId())) {\n    throw new IllegalArgumentException(\"SamlRegisteredService requires a non-blank serviceId/entityId\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["saml","configuration","cache-expiration","missing-entity-id"],"backgroundTag":"missing-required-config-field","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}