apereo/cas · warning

Attribute repository caching is disabled

Error message

Attribute repository caching is disabled

What it means

The cachingAttributeRepository bean method builds the Caffeine-backed CachingPersonAttributeDaoImpl only when a positive expiration time is configured. When cas.authn.attributeRepository.core.expirationTime is <= 0, caching is skipped entirely and the raw aggregating attribute repository is returned, with this warn explaining why.

Solutions

  1. Set cas.authn.attributeRepository.core.expirationTime to a positive duration (e.g. PT30M or seconds value)
  2. Set expirationTime to 0 intentionally only in dev, and silence/expect the warn
  3. Verify the property is read from the correct config source and not overridden by an environment variable
  4. If no caching is desired, leave as-is but rely on the underlying repository's own caching

Example fix

# before
cas.authn.attributeRepository.core.expirationTime=0
# after
cas.authn.attributeRepository.core.expirationTime=PT2H
Defensive patterns

Strategy: validation

Validate before calling

long expiration = casProperties.getAuthn().getAttributeRepository().getCore().getExpirationTime();
if (expiration <= 0) {
    log.warn("Attribute repository caching disabled (expirationTime={})", expiration);
}

Prevention

When it happens

Trigger: cachingAttributeRepository bean is created while cas.authn.attributeRepository.core.expirationTime is 0 or negative (or unset and defaulting to 0).

Common situations: Expiration property never set in cas.properties/application.yml; expiration deliberately set to 0 for development to always see fresh attribute lookups; property typo'd so the default of 0 applies; config migrated from a version with a different default.

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/26109e4f175ac385. Report an issue: GitHub.

Appendix: source

Thrown at support/cas-server-support-person-directory/src/main/java/org/apereo/cas/config/CasPersonDirectoryConfiguration.java:184

        @ConditionalOnMissingBean(name = AttributeRepositoryResolver.BEAN_NAME)
        public AttributeRepositoryResolver attributeRepositoryResolver(
            @Qualifier(TenantExtractor.BEAN_NAME)
            final TenantExtractor tenantExtractor,
            final CasConfigurationProperties casProperties,
            @Qualifier(ServicesManager.BEAN_NAME) final ServicesManager servicesManager) {
            return new DefaultAttributeRepositoryResolver(servicesManager, tenantExtractor, casProperties);
        }

        @Bean(name = {"cachingAttributeRepository", PrincipalResolver.BEAN_NAME_ATTRIBUTE_REPOSITORY})
        @ConditionalOnMissingBean(name = {"cachingAttributeRepository", PrincipalResolver.BEAN_NAME_ATTRIBUTE_REPOSITORY})
        @RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
        public PersonAttributeDao cachingAttributeRepository(
            final CasConfigurationProperties casProperties,
            @Qualifier("aggregatingAttributeRepository")
            final PersonAttributeDao aggregatingAttributeRepository) {
            val props = casProperties.getAuthn().getAttributeRepository().getCore();
            if (props.getExpirationTime() <= 0) {
                LOGGER.warn("Attribute repository caching is disabled");
                return aggregatingAttributeRepository;
            }

            val impl = new CachingPersonAttributeDaoImpl();
            impl.setCacheNullResults(false);
            val userinfoCache = Caffeine.newBuilder()
                .maximumSize(props.getMaximumCacheSize())
                .expireAfterWrite(props.getExpirationTime(), TimeUnit.valueOf(props.getExpirationTimeUnit().toUpperCase(Locale.ENGLISH)))
                .build();
            impl.setUserInfoCache((Map) userinfoCache.asMap());
            impl.setCachedPersonAttributesDao(aggregatingAttributeRepository);
            LOGGER.trace("Configured cache expiration policy for attribute sources to be [{}] minute(s)", props.getExpirationTime());
            return impl;
        }

        @Bean
        @RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
        @ConditionalOnMissingBean(name = "attributeRepositoryAttributeMerger")

View on GitHub (pinned to e7288fc434)