{"record":{"id":"f5ca4d78a721b8fd","repo":"quarkusio/quarkus","slug":"thread-pool-class-does-not-implement-threadpool-in","errorCode":null,"errorMessage":"Thread pool class does not implement ThreadPool interface spi: ${threadPoolClass}","messagePattern":"Thread pool class does not implement ThreadPool interface spi: (.+?)","errorType":"exception","errorClass":"ConfigurationException","httpStatus":null,"severity":"error","filePath":"extensions/quartz/deployment/src/main/java/io/quarkus/quartz/deployment/QuartzProcessor.java","lineNumber":245,"sourceCode":"            QuartzJDBCDriverDialectBuildItem driverDialect, List<JdbcDataSourceBuildItem> jdbcDataSourceBuildItems) {\n        List<ReflectiveClassBuildItem> reflectiveClasses = new ArrayList<>();\n\n        if (config.serializeJobData()) {\n            reflectiveClasses.add(ReflectiveClassBuildItem.builder(\n                    String.class,\n                    JobDataMap.class,\n                    DirtyFlagMap.class,\n                    StringKeyDirtyFlagMap.class,\n                    HashMap.class)\n                    .reason(getClass().getName())\n                    .serialization(true).build());\n        }\n\n        Class<?> threadPoolClass;\n        try {\n            threadPoolClass = Class.forName(config.threadPoolClass(), false, Thread.currentThread().getContextClassLoader());\n            if (!ThreadPool.class.isAssignableFrom(threadPoolClass)) {\n                throw new ConfigurationException(\n                        \"Thread pool class does not implement ThreadPool interface spi: \" + config.threadPoolClass());\n            }\n        } catch (ClassNotFoundException e) {\n            throw new ConfigurationException(\"Thread pool class not found: \" + config.threadPoolClass());\n        }\n\n        reflectiveClasses.add(ReflectiveClassBuildItem.builder(threadPoolClass, SimpleInstanceIdGenerator.class)\n                .reason(getClass().getName())\n                .methods().build());\n        reflectiveClasses\n                .add(ReflectiveClassBuildItem.builder(CascadingClassLoadHelper.class, InitThreadContextClassLoadHelper.class)\n                        .reason(getClass().getName())\n                        .build());\n        reflectiveClasses.add(ReflectiveClassBuildItem.builder(config.storeType().clazz)\n                .reason(getClass().getName())\n                .methods().fields().build());\n\n        if (config.storeType().isDbStore()) {","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/quartz/deployment/src/main/java/io/quarkus/quartz/deployment/QuartzProcessor.java#L227-L263","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (application.properties)\nquarkus.quartz.thread-pool-class=java.util.concurrent.ThreadPoolExecutor\n\n// after\nquarkus.quartz.thread-pool-class=org.quartz.simpl.SimpleThreadPool\n// or a custom class:\n// public class MyThreadPool implements org.quartz.spi.ThreadPool { ... }","handlingStrategy":"validation","validationCode":"Class<?> c = Class.forName(\"com.example.MyThreadPool\", false,\n    Thread.currentThread().getContextClassLoader());\nif (!org.quartz.spi.ThreadPool.class.isAssignableFrom(c)) {\n    throw new IllegalStateException(c.getName() + \" must implement org.quartz.spi.ThreadPool\");\n}","typeGuard":"static boolean isThreadPool(Class<?> c) {\n    return org.quartz.spi.ThreadPool.class.isAssignableFrom(c);\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["quarkus","quartz","thread-pool","spi","configuration"],"backgroundTag":"interface-not-implemented","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}