{"record":{"id":"26109e4f175ac385","repo":"apereo/cas","slug":"attribute-repository-caching-is-disabled","errorCode":null,"errorMessage":"Attribute repository caching is disabled","messagePattern":"Attribute repository caching is disabled","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"support/cas-server-support-person-directory/src/main/java/org/apereo/cas/config/CasPersonDirectoryConfiguration.java","lineNumber":184,"sourceCode":"        @ConditionalOnMissingBean(name = AttributeRepositoryResolver.BEAN_NAME)\n        public AttributeRepositoryResolver attributeRepositoryResolver(\n            @Qualifier(TenantExtractor.BEAN_NAME)\n            final TenantExtractor tenantExtractor,\n            final CasConfigurationProperties casProperties,\n            @Qualifier(ServicesManager.BEAN_NAME) final ServicesManager servicesManager) {\n            return new DefaultAttributeRepositoryResolver(servicesManager, tenantExtractor, casProperties);\n        }\n\n        @Bean(name = {\"cachingAttributeRepository\", PrincipalResolver.BEAN_NAME_ATTRIBUTE_REPOSITORY})\n        @ConditionalOnMissingBean(name = {\"cachingAttributeRepository\", PrincipalResolver.BEAN_NAME_ATTRIBUTE_REPOSITORY})\n        @RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)\n        public PersonAttributeDao cachingAttributeRepository(\n            final CasConfigurationProperties casProperties,\n            @Qualifier(\"aggregatingAttributeRepository\")\n            final PersonAttributeDao aggregatingAttributeRepository) {\n            val props = casProperties.getAuthn().getAttributeRepository().getCore();\n            if (props.getExpirationTime() <= 0) {\n                LOGGER.warn(\"Attribute repository caching is disabled\");\n                return aggregatingAttributeRepository;\n            }\n\n            val impl = new CachingPersonAttributeDaoImpl();\n            impl.setCacheNullResults(false);\n            val userinfoCache = Caffeine.newBuilder()\n                .maximumSize(props.getMaximumCacheSize())\n                .expireAfterWrite(props.getExpirationTime(), TimeUnit.valueOf(props.getExpirationTimeUnit().toUpperCase(Locale.ENGLISH)))\n                .build();\n            impl.setUserInfoCache((Map) userinfoCache.asMap());\n            impl.setCachedPersonAttributesDao(aggregatingAttributeRepository);\n            LOGGER.trace(\"Configured cache expiration policy for attribute sources to be [{}] minute(s)\", props.getExpirationTime());\n            return impl;\n        }\n\n        @Bean\n        @RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)\n        @ConditionalOnMissingBean(name = \"attributeRepositoryAttributeMerger\")","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-person-directory/src/main/java/org/apereo/cas/config/CasPersonDirectoryConfiguration.java#L166-L202","documentation":"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.","triggerScenarios":"cachingAttributeRepository bean is created while cas.authn.attributeRepository.core.expirationTime is 0 or negative (or unset and defaulting to 0).","commonSituations":"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.","solutions":["Set cas.authn.attributeRepository.core.expirationTime to a positive duration (e.g. PT30M or seconds value)","Set expirationTime to 0 intentionally only in dev, and silence/expect the warn","Verify the property is read from the correct config source and not overridden by an environment variable","If no caching is desired, leave as-is but rely on the underlying repository's own caching"],"exampleFix":"# before\ncas.authn.attributeRepository.core.expirationTime=0\n# after\ncas.authn.attributeRepository.core.expirationTime=PT2H","handlingStrategy":"validation","validationCode":"long expiration = casProperties.getAuthn().getAttributeRepository().getCore().getExpirationTime();\nif (expiration <= 0) {\n    log.warn(\"Attribute repository caching disabled (expirationTime={})\", expiration);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set cas.authn.attributeRepository.core.expirationTime explicitly in every environment","Watch for this warn at startup as the signal that caching silently skipped","Keep expiration settings in the shared CAS properties template, not per-environment ad-hoc files"],"tags":["caching","attribute-repository","configuration"],"backgroundTag":"invalid-config-value","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"}