When configuring Thymeleaf in Spring Boot 3.4.3 with JDK 17, developers may encounter unexpected template resolution failures when packaging the application as a JAR — even though everything works flawlessly in IDE environments like IntelliJ or Eclipse.
This issue typically surfaces when a custom configuration class implements WebMvcConfigurer. While the default auto-configuration handles Thymeleaf correctly out-of-the-box, introducing manual configuration can interfere with resource resolution paths, especially under JAR deployment.
The error message: org.thymeleaf.exceptions.TemplateInputException: An error happende during template parsing (template: "class path resource [static//catch/catch-index.html]") indicates that the resolver is incorrectly concatenating paths, often due to conflicting prefix settings.
A common misstep is defining the template prefix as classpath:/static/ in a custom ITemplateResolver bean while also leaving Thymeleaf-related properties in application.yml. These two configurations can conflict, causing the resolver to double-prefix paths (e.g., static//catch/...).
To resolve this:
- Remove all Thymeleaf configuration from application.yml when using programmatic configuration:
# Comment out or remove these lines:
# spring:
# thymeleaf:
# prefix: classpath:/static/
# suffix: .html
# cacheable: false
- Use relative paths in ModelAndView without a leading slash:
@RequestMapping("/catch")
public ModelAndView handleCatch(@RequestParam(value = "code", required = false) String code) {
ModelAndView mv = new ModelAndView("catch/catch-index.html"); // ✅ Correct
// ModelAndView mv = new ModelAndView("/catch/catch-index.html"); // ❌ Avoid leading slash
return mv;
}
- Define the resolver with a clean prefix:
@Bean
public ITemplateResolver templateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setPrefix("classpath:/static/"); // Must end with /
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
resolver.setCacheable(false);
return resolver;
}
@Bean
public TemplateEngine templateEngine(ITemplateResolver resolver) {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(resolver);
return engine;
}
The root cause lies in how Spring Boot's auto-configuration and custom WebMvcConfigurer interact with resource resolution. When both are present, the framwork may apply path normalization inconsistently — particularly in packaged JARs where classpath resource access differs from development mode.
Additionally, leading slashes in view names trigger an internal path concatenation bug in certain Spring Boot versions when paired with non-default resolver prefixes. Omitting the slash ensures the resolver appends the path correctly to the configured prefix.
This behavior is not clearly documented and can be easily missed during migration or refactoring. Always test template resolution in a packaged JAR, not just in development mode.