apereo/cas · warning

Custom theme [ ] for service [ ] cannot be located. Falling…

Error message

Custom theme [{}] for service [{}] cannot be located. Falling back to default theme...

What it means

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.

Solutions

  1. Verify the theme's properties resource exists at the basename CAS expects (e.g. classpath:/<theme>/theme.properties).
  2. Correct the theme name in the registered service definition.
  3. Deploy the theme resources (templates + properties) into the CAS overlay.
  4. Check AggregateCasThemeSource/thymeleaf configuration includes the theme's resource location.

Example fix

// before (service JSON)
"theme": "custom-thme"
// after
"theme": "custom-theme"
Defensive patterns

Strategy: validation

Validate before calling

// confirm the theme bundle exists for the service's configured theme name
String theme = registeredService.getTheme();
if (theme != null && getClass().getResource("/" + theme + "/theme.properties") == null)
    LOGGER.warn("Theme {} has no theme.properties on classpath", theme);

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/1cbe8f8f4c974988. Report an issue: GitHub.

Appendix: source

Thrown at support/cas-server-support-themes-core/src/main/java/org/apereo/cas/services/web/RegisteredServiceThemeResolver.java:128

                val exec = HttpExecutionRequest.builder()
                    .parameters(CollectionUtils.wrap("service", service.getId()))
                    .url(url)
                    .method(HttpMethod.GET)
                    .build();
                response = HttpUtils.execute(exec);
                if (response != null && response.getCode() == HttpStatus.SC_OK) {
                    try (val content = ((HttpEntityContainer) response).getEntity().getContent()) {
                        val result = IOUtils.toString(content, StandardCharsets.UTF_8);
                        return StringUtils.defaultIfBlank(result, getDefaultThemeName());
                    }
                }
            }
            val theme = resolveThemeForService(registeredService, request);
            if (theme != null) {
                LOGGER.trace("Found custom theme [{}] for service [{}]", theme, registeredService);
                return theme;
            }
            LOGGER.warn("Custom theme [{}] for service [{}] cannot be located. Falling back to default theme...",
                registeredService.getTheme(), registeredService.getName());
        } catch (final Exception e) {
            LoggingUtils.error(LOGGER, e);
        } finally {
            HttpUtils.close(response);
        }
        return getDefaultThemeName();
    }

    protected String determineThemeFromGroovyResource(final HttpServletRequest request,
                                                      final Service service,
                                                      final WebBasedRegisteredService registeredService,
                                                      final AbstractResource resource) {
        LOGGER.debug("Executing groovy script to determine theme for [{}]", service.getId());
        return ApplicationContextProvider.getScriptResourceCacheManager()
            .map(cacheManager -> FunctionUtils.doUnchecked(() -> {
                val filePath = resource.getFile().getCanonicalPath();
                val script = cacheManager.resolveScriptableResource(resource.getFile().toURI().toString(), filePath);

View on GitHub (pinned to e7288fc434)