quarkusio/quarkus · error · IllegalStateException
Template builder already specified for: ${rootCauseClassName
Error message
Template builder already specified for: ${rootCauseClassName} What it means
ErrorPageGenerators.register() maps a root-cause exception class name to a function that renders a custom error page in dev mode. Only one generator per class is allowed; registering a second generator for the same class name throws this IllegalStateException.
Source
Thrown at core/devmode-spi/src/main/java/io/quarkus/dev/ErrorPageGenerators.java:26
* The generators can be used to generate a custom HTML page for a specific deployment exception that occurs during the
* development mode.
* <p>
* In order to avoid classloading issues the generators should not access the root cause directly but use reflection instead
* (the exception class could be loaded by a different class loader).
*/
public class ErrorPageGenerators {
private static final Map<String, Function<Throwable, String>> generators = new ConcurrentHashMap<>();
/**
* Register a function that will be used to generate the error page for the given root cause.
*
* @param rootCauseClassName
* @param function
*/
public static void register(String rootCauseClassName, Function<Throwable, String> function) {
if (generators.putIfAbsent(rootCauseClassName, function) != null) {
throw new IllegalStateException("Template builder already specified for: " + rootCauseClassName);
}
}
public static Function<Throwable, String> get(String rootCauseClassName) {
return generators.get(rootCauseClassName);
}
// This method is called by a relevant service provider during HotReplacementSetup#close()
public static void clear() {
generators.clear();
}
}
View on GitHub (pinned to e1c734241f)
Solutions
- Remove one of the duplicate register() calls for the same class name
- Guard your registration with ErrorPageGenerators.get(className) == null before registering
- On hot reload, make registration idempotent (check before register)
Example fix
// before
ErrorPageGenerators.register("com.acme.MyException", fn);
// after
if (ErrorPageGenerators.get("com.acme.MyException") == null) {
ErrorPageGenerators.register("com.acme.MyException", fn);
} Defensive patterns
Strategy: validation
Validate before calling
String cls = "com.acme.MyException";
if (ErrorPageGenerators.get(cls) == null) {
ErrorPageGenerators.register(cls, fn);
} Try / catch
try { ErrorPageGenerators.register(cls, fn); } catch (IllegalStateException e) { if (e.getMessage().startsWith("Template builder already specified")) { /* skip or replace existing registration */ } else { throw e; } } Prevention
- Check get(className) before register()
- Coordinate with extensions that may register the same exception
- Make registration idempotent for hot-reload cycles
When it happens
Trigger: Calling ErrorPageGenerators.register(className, fn) twice with the same rootCauseClassName — e.g. two extensions or a hot-redeployed classpath registering the same exception handler again.
Common situations: Two extensions both registering handlers for the same exception type; dev-mode hot reload re-invoking registration code; user code registering a custom handler that collides with an extension's handler.
Related errors
- Unable to deserialize the dev mode context. Does the Quarkus
- Hot deployment of the application is not supported when upda
- remote-dev can only be used with mutable applications i.e. u
- Failed to create compiler
- Failed to open class path file <file>
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/5e00ca5eb08fa294.
Report an issue: GitHub.