quarkusio/quarkus · error · ConfigurationException
Thread pool class does not implement ThreadPool interface sp
Error message
Thread pool class does not implement ThreadPool interface spi: ${threadPoolClass} What it means
During the reflectiveClasses build step, QuartzProcessor loads the class configured via quarkus.quartz.thread-pool-class and verifies it implements org.quartz.spi.ThreadPool, since it is passed to Quartz's scheduler. The class loaded fine but does not implement that SPI interface, so the build fails. Quartz requires any thread pool to honor this interface.
Source
Thrown at extensions/quartz/deployment/src/main/java/io/quarkus/quartz/deployment/QuartzProcessor.java:245
QuartzJDBCDriverDialectBuildItem driverDialect, List<JdbcDataSourceBuildItem> jdbcDataSourceBuildItems) {
List<ReflectiveClassBuildItem> reflectiveClasses = new ArrayList<>();
if (config.serializeJobData()) {
reflectiveClasses.add(ReflectiveClassBuildItem.builder(
String.class,
JobDataMap.class,
DirtyFlagMap.class,
StringKeyDirtyFlagMap.class,
HashMap.class)
.reason(getClass().getName())
.serialization(true).build());
}
Class<?> threadPoolClass;
try {
threadPoolClass = Class.forName(config.threadPoolClass(), false, Thread.currentThread().getContextClassLoader());
if (!ThreadPool.class.isAssignableFrom(threadPoolClass)) {
throw new ConfigurationException(
"Thread pool class does not implement ThreadPool interface spi: " + config.threadPoolClass());
}
} catch (ClassNotFoundException e) {
throw new ConfigurationException("Thread pool class not found: " + config.threadPoolClass());
}
reflectiveClasses.add(ReflectiveClassBuildItem.builder(threadPoolClass, SimpleInstanceIdGenerator.class)
.reason(getClass().getName())
.methods().build());
reflectiveClasses
.add(ReflectiveClassBuildItem.builder(CascadingClassLoadHelper.class, InitThreadContextClassLoadHelper.class)
.reason(getClass().getName())
.build());
reflectiveClasses.add(ReflectiveClassBuildItem.builder(config.storeType().clazz)
.reason(getClass().getName())
.methods().fields().build());
if (config.storeType().isDbStore()) {View on GitHub (pinned to e1c734241f)
Solutions
- Point quarkus.quartz.thread-pool-class at a class implementing org.quartz.spi.ThreadPool, e.g. io.quarkus.quartz.runtime.QuarkusSimpleThreadPool (the default) or org.quartz.simpl.SimpleThreadPool.
- If you meant a JDK executor, wrap it in a class that implements org.quartz.spi.ThreadPool instead of referencing it directly.
- Remove the property entirely to use the Quarkus default thread pool.
- If the class was refactored, make it implement ThreadPool again or update the config to the correct class.
Example fix
// before (application.properties)
quarkus.quartz.thread-pool-class=java.util.concurrent.ThreadPoolExecutor
// after
quarkus.quartz.thread-pool-class=org.quartz.simpl.SimpleThreadPool
// or a custom class:
// public class MyThreadPool implements org.quartz.spi.ThreadPool { ... } Defensive patterns
Strategy: validation
Validate before calling
Class<?> c = Class.forName("com.example.MyThreadPool", false,
Thread.currentThread().getContextClassLoader());
if (!org.quartz.spi.ThreadPool.class.isAssignableFrom(c)) {
throw new IllegalStateException(c.getName() + " must implement org.quartz.spi.ThreadPool");
} Type guard
static boolean isThreadPool(Class<?> c) {
return org.quartz.spi.ThreadPool.class.isAssignableFrom(c);
} Prevention
- Remember the property expects an org.quartz.spi.ThreadPool implementation, not a java.util.concurrent executor.
- Use QuarkusSimpleThreadPool (default) unless you truly need a custom pool.
- Add a unit test asserting isThreadPool() for the configured class.
- Wrap JDK executors in an adapter class implementing ThreadPool if you must reuse them.
When it happens
Trigger: Setting quarkus.quartz.thread-pool-class=<fqcn> to a class that does not implement org.quartz.spi.ThreadPool - e.g. a java.util.concurrent ExecutorService implementation, a custom pool class, or an unrelated class; or a custom pool whose ThreadPool implementation was removed in a refactor/upgrade.
Common situations: Misreading the property as accepting JDK executor implementations; copying a class name from plain Quartz configs of a different type; dependency upgrades that changed what the class name resolves to.
Related errors
- Clustered jobs configured with unsupported job store option
- Quartz datasource resolution can be either deferred to runti
- JDBC Store configured but the '%s' datasource is not configu
- Thread pool class not found: ${threadPoolClass}
- %s does not implement %s
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/f5ca4d78a721b8fd.
Report an issue: GitHub.