{"record":{"id":"1cbe8f8f4c974988","repo":"apereo/cas","slug":"custom-theme-for-service-cannot-be-locat","errorCode":null,"errorMessage":"Custom theme [{}] for service [{}] cannot be located. Falling back to default theme...","messagePattern":"Custom theme \\[(.+?)\\] for service \\[(.+?)\\] cannot be located\\. Falling back to default theme\\.\\.\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"support/cas-server-support-themes-core/src/main/java/org/apereo/cas/services/web/RegisteredServiceThemeResolver.java","lineNumber":128,"sourceCode":"                val exec = HttpExecutionRequest.builder()\n                    .parameters(CollectionUtils.wrap(\"service\", service.getId()))\n                    .url(url)\n                    .method(HttpMethod.GET)\n                    .build();\n                response = HttpUtils.execute(exec);\n                if (response != null && response.getCode() == HttpStatus.SC_OK) {\n                    try (val content = ((HttpEntityContainer) response).getEntity().getContent()) {\n                        val result = IOUtils.toString(content, StandardCharsets.UTF_8);\n                        return StringUtils.defaultIfBlank(result, getDefaultThemeName());\n                    }\n                }\n            }\n            val theme = resolveThemeForService(registeredService, request);\n            if (theme != null) {\n                LOGGER.trace(\"Found custom theme [{}] for service [{}]\", theme, registeredService);\n                return theme;\n            }\n            LOGGER.warn(\"Custom theme [{}] for service [{}] cannot be located. Falling back to default theme...\",\n                registeredService.getTheme(), registeredService.getName());\n        } catch (final Exception e) {\n            LoggingUtils.error(LOGGER, e);\n        } finally {\n            HttpUtils.close(response);\n        }\n        return getDefaultThemeName();\n    }\n\n    protected String determineThemeFromGroovyResource(final HttpServletRequest request,\n                                                      final Service service,\n                                                      final WebBasedRegisteredService registeredService,\n                                                      final AbstractResource resource) {\n        LOGGER.debug(\"Executing groovy script to determine theme for [{}]\", service.getId());\n        return ApplicationContextProvider.getScriptResourceCacheManager()\n            .map(cacheManager -> FunctionUtils.doUnchecked(() -> {\n                val filePath = resource.getFile().getCanonicalPath();\n                val script = cacheManager.resolveScriptableResource(resource.getFile().toURI().toString(), filePath);","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-themes-core/src/main/java/org/apereo/cas/services/web/RegisteredServiceThemeResolver.java#L110-L146","documentation":"In RegisteredServiceThemeResolver.determineThemeNameToChoose, after the service is found and resolveThemeForService returns null, CAS warns that the service's configured custom theme cannot be located and falls back to the default theme. resolveThemeForService returns null when no message bundle for the theme name can be resolved, so this indicates the theme resources are missing or unreachable.","triggerScenarios":"A registered service has theme property set, but the corresponding resource bundle (classpath:/theme-name/theme.properties or similar) cannot be resolved for the request, so resolveThemeForService returns null.","commonSituations":"Theme name typo in the service JSON; theme resources not deployed in this webapp/overlay; theme bundle exists only under a different basename; theme resource removed during upgrade.","solutions":["Verify the theme's properties resource exists at the basename CAS expects (e.g. classpath:/<theme>/theme.properties).","Correct the theme name in the registered service definition.","Deploy the theme resources (templates + properties) into the CAS overlay.","Check AggregateCasThemeSource/thymeleaf configuration includes the theme's resource location."],"exampleFix":"// before (service JSON)\n\"theme\": \"custom-thme\"\n// after\n\"theme\": \"custom-theme\"","handlingStrategy":"validation","validationCode":"// confirm the theme bundle exists for the service's configured theme name\nString theme = registeredService.getTheme();\nif (theme != null && getClass().getResource(\"/\" + theme + \"/theme.properties\") == null)\n    LOGGER.warn(\"Theme {} has no theme.properties on classpath\", theme);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Standardize theme names to match resource directory names exactly.","Ship theme resources with the service definitions that reference them.","Test each registered service theme in a staging environment."],"tags":["themes","resource-not-found","service-registry","fallback"],"backgroundTag":"resource-not-found","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"}