apereo/cas · warning

Could not add template prefix

Error message

Could not add template prefix '%s' to resolver: [%s]

What it means

CasThymeleafChainingTemplateViewResolver setup in CasThymeleafAutoConfiguration.iterates over configured view/template paths and, for each prefix, creates a ClassLoaderTemplateResolver or FileTemplateResolver and adds it to the resolver chain. If constructing/configuring the resolver for a prefix throws, the failure is logged with this message and that prefix is skipped; remaining resolvers (theme and default classpath resolvers) still get added.

Solutions

  1. Fix the offending template prefix entry in configuration (cas.view.template-prefixes or theme view paths).
  2. Ensure filesystem-based prefixes point to existing, readable directories.
  3. Use ResourceUtils.CLASSPATH_URL_PREFIX (classpath:) only for resources actually on the classpath.
  4. Check the chained exception (stack trace logged alongside) for the root resolver error.

Example fix

// before
cas.view.template-prefixes[0]=file:/etc/cas/templates/temlates/
// after
cas.view.template-prefixes[0]=file:/etc/cas/templates/templates/
Defensive patterns

Strategy: validation

Validate before calling

// validate each configured prefix before startup
casProperties.getView().getTemplatePrefixes().forEach(p -> {
    if (p.startsWith("file:") && !java.nio.file.Files.isDirectory(java.nio.file.Path.of(URI.create(p))))
        LOGGER.warn("Template prefix is not a directory: {}", p);
});

Prevention

When it happens

Trigger: An exception is thrown while creating/configuring the template resolver for a configured prefix — e.g. the view path is malformed, an invalid URL/resource prefix, or resolver configuration fails for the given thymeleaf properties.

Common situations: Typo or unsupported scheme in a configured template prefix (e.g. bad cas.view.template-prefixes entry); directory expected on disk missing so FileTemplateResolver setup/validation fails; classpath prefix spelled incorrectly.

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/15c0c808f90c1852. Report an issue: GitHub.

Appendix: source

Thrown at support/cas-server-support-thymeleaf/src/main/java/org/apereo/cas/config/CasThymeleafAutoConfiguration.java:167

        templatePrefixes.forEach(prefix -> {
            try {
                val prefixPath = prefix.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX)
                    ? prefix
                    : ResourceUtils.getFile(prefix).getCanonicalPath();
                val viewPath = Strings.CI.appendIfMissing(prefixPath, "/");
                val theme = prefix.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX)
                    ? new ThemeClassLoaderTemplateResolver(themeResolver)
                    : new ThemeFileTemplateResolver(casProperties, themeResolver);
                configureTemplateViewResolver(theme, thymeleafProperties);
                theme.setPrefix(Strings.CI.removeStart(viewPath, ResourceUtils.CLASSPATH_URL_PREFIX) + "themes/%s/");
                chain.addResolver(theme);

                val template = prefix.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX) ? new ClassLoaderTemplateResolver() : new FileTemplateResolver();
                configureTemplateViewResolver(template, thymeleafProperties);
                template.setPrefix(Strings.CI.removeStart(viewPath, ResourceUtils.CLASSPATH_URL_PREFIX));
                chain.addResolver(template);
            } catch (final Exception e) {
                LoggingUtils.warn(LOGGER,
                    String.format("Could not add template prefix '%s' to resolver: [%s]", prefix, e.getMessage()), e);
            }
        });

        chain.addResolver(themeClassLoaderTemplateResolver);
        chain.addResolver(classLoaderTemplateResolver);
        chain.initialize();
        return chain;
    }

    @Bean
    @ConditionalOnMissingBean(name = "themeClassLoaderTemplateResolver")
    @RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
    public ITemplateResolver themeClassLoaderTemplateResolver(final ThymeleafProperties thymeleafProperties,
                                                              @Qualifier("themeResolver") final ThemeResolver themeResolver) {
        val themeCp = new ThemeClassLoaderTemplateResolver(themeResolver);
        configureTemplateViewResolver(themeCp, thymeleafProperties);
        themeCp.setPrefix("templates/%s/");

View on GitHub (pinned to e7288fc434)