quarkusio/quarkus · error · IllegalArgumentException
%s does not implement %s
Error message
%s does not implement %s
What it means
checkExtensionPoints validates each configured Quartz extension point (JobListener, TriggerListener, etc.) by loading its class and checking that it is assignable from the required interface/parent class. If the class exists but does not implement the required type, an IllegalArgumentException stating '<class> does not implement <type>' is thrown at build time.
Source
Thrown at extensions/quartz/deployment/src/main/java/io/quarkus/quartz/deployment/QuartzProcessor.java:383
if (m.getMethod().hasAnnotation(NONCONCURRENT)) {
nonconcurrentMethods.add(m.getMethod().declaringClass().name() + "#" + m.getMethod().name());
}
}
syntheticBeanBuildItemBuildProducer.produce(SyntheticBeanBuildItem.configure(QuartzSupport.class)
.scope(Singleton.class) // this should be @ApplicationScoped but it fails for some reason
.setRuntimeInit()
.supplier(recorder.quartzSupportSupplier(driverDialect.getDriver(), driverDialect.getDataSources(),
nonconcurrentMethods))
.done());
}
private static void checkExtensionPoints(Map<String, QuartzExtensionPointConfig> config, Class<?> clazz) {
for (QuartzExtensionPointConfig extensionPointConfig : config.values()) {
try {
if (!clazz.isAssignableFrom(
Class.forName(extensionPointConfig.clazz(), false, Thread.currentThread().getContextClassLoader()))) {
throw new IllegalArgumentException(
String.format("%s does not implement %s", extensionPointConfig.clazz(), clazz));
}
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException(e);
}
}
}
}
View on GitHub (pinned to e1c734241f)
Solutions
- Make the configured class implement/extend the required Quartz SPI type (e.g. org.quartz.JobListener).
- Check you put the class under the correct config section for its actual type.
- Verify against the Quartz API for the version on the classpath — interface names may differ across versions.
Example fix
// before
public class MyListener { /* no interface */ }
// after
public class MyListener implements org.quartz.JobListener { ... } Defensive patterns
Strategy: validation
Validate before calling
// before referencing in config, verify the SPI contract
Class<?> c = Class.forName("com.myapp.MyListener", false,
Thread.currentThread().getContextClassLoader());
if (!org.quartz.JobListener.class.isAssignableFrom(c)) {
throw new IllegalStateException("configured listener must implement org.quartz.JobListener");
} Prevention
- Always implement the exact Quartz SPI interface matching the config section (JobListener vs TriggerListener).
- Double-check the config property section before pasting shared listener config.
- Add an application-level unit test asserting isAssignableFrom for all configured extension-point classes.
When it happens
Trigger: Configure a class under quarkus.quartz.<extension-point> (e.g. job-listeners, store-classes) whose class loads successfully but does not extend/implement the required Quartz SPI type, e.g. a listener class that doesn't implement JobListener.
Common situations: Pointing a listener config at a plain class or wrong listener type (JobListener vs TriggerListener confusion); implementing the wrong interface after a refactor; copying config between properties of different extension point kinds.
Related errors
- Offending class is '${className}'
- Clustered jobs configured with unsupported job store option
- The Agroal extension is missing and it is required when a Qu
- Custom JDBC delegate implementation class '%s' was not found
- Custom JDBC delegate implementation with name '%s' needs to
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/554e7d8e3c96f637.
Report an issue: GitHub.