quarkusio/quarkus · error · UnableToInterruptJobException
Job ${beanClass} can not be interrupted, since it does not i
Error message
Job ${beanClass} can not be interrupted, since it does not implement org.quartz.InterruptableJob What it means
CdiAwareJob wraps CDI-managed @Scheduled job beans. Its interrupt() delegates to the job only if the bean class implements org.quartz.InterruptableJob; otherwise it throws UnableToInterruptJobException with this message. Quartz invokes interrupt() when a job is interrupted via scheduler.interrupt(jobKey) or on scheduler shutdown with interruption requested.
Source
Thrown at extensions/quartz/runtime/src/main/java/io/quarkus/quartz/runtime/CdiAwareJob.java:51
try {
beanInstance.execute(context);
} catch (JobExecutionException e) {
refire = e.refireImmediately();
throw e;
} finally {
if (refire != true && handle.getBean().getScope().equals(Dependent.class)) {
handle.destroy();
}
}
}
@Override
public void interrupt() throws UnableToInterruptJobException {
// delegate if possible; throw an exception in other cases
if (InterruptableJob.class.isAssignableFrom(handle.getBean().getBeanClass())) {
((InterruptableJob) beanInstance).interrupt();
} else {
throw new UnableToInterruptJobException("Job " + handle.getBean().getBeanClass()
+ " can not be interrupted, since it does not implement " + InterruptableJob.class.getName());
}
}
}
View on GitHub (pinned to e1c734241f)
Solutions
- Make the job bean implement org.quartz.InterruptableJob and handle interruption in interrupt().
- Redesign the job to check a cancellation flag/thread interruption instead of relying on Quartz interrupt.
- Catch UnableToInterruptJobException at the interrupt call site and handle non-interruptible jobs gracefully.
Example fix
// before
@Scheduled(cron = "0 0 * * * ?")
public class ReportJob { public void run() { ... } }
// after
@Scheduled(cron = "0 0 * * * ?")
public class ReportJob implements org.quartz.InterruptableJob {
public void execute(JobExecutionContext ctx) { while (!Thread.currentThread().isInterrupted()) { ... } }
public void interrupt() { Thread.currentThread().interrupt(); }
} Defensive patterns
Strategy: type-guard
Validate before calling
// check before requesting interruption Class<?> beanClass = jobHandle.getBean().getBeanClass(); boolean interruptible = org.quartz.InterruptableJob.class.isAssignableFrom(beanClass);
Type guard
static boolean isInterruptableJob(Class<?> beanClass) {
return beanClass != null && org.quartz.InterruptableJob.class.isAssignableFrom(beanClass);
} Try / catch
try {
scheduler.interrupt(jobKey);
} catch (org.quartz.UnableToInterruptJobException e) {
// job does not implement InterruptableJob: stop it another way
log.warn("Job not interruptible: " + jobKey);
} catch (org.quartz.SchedulerException e) {
log.error("Failed to interrupt job", e);
} Prevention
- Implement InterruptableJob on any long-running @Scheduled bean you may need to cancel.
- Use a volatile cancellation flag checked inside the job loop.
- Document which jobs are interruptible when exposing admin stop endpoints.
When it happens
Trigger: Call scheduler.interrupt(jobKey) (or trigger shutdown-with-interrupt) for a @Scheduled CDI job bean whose class does not implement InterruptableJob.
Common situations: Attempting to cancel long-running scheduled methods programmatically; stopping the app while a long job runs; assuming all Quartz jobs are interruptible.
Related errors
- Quartz scheduler is either explicitly disabled through quark
- SchedulerException while scheduling job (no message)
- Multiple @Inject constructors on ${theClass}
- Quarkus does not support CDI Full @Specializes annotation; t
- IllegalStateException wrapping ClassNotFoundException for ge
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/277bd8f986aba573.
Report an issue: GitHub.