{"record":{"id":"63df5dde402765a8","repo":"quarkusio/quarkus","slug":"cannot-load-task-class-taskclass","errorCode":null,"errorMessage":"Cannot load task class: {taskClass}","messagePattern":"Cannot load task class: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"extensions/quartz/runtime/src/main/java/io/quarkus/quartz/runtime/QuartzSchedulerImpl.java","lineNumber":1292,"sourceCode":"\n    static class SerializedExecutionMetadata implements ExecutionMetadata {\n\n        private final Class<? extends Consumer<ScheduledExecution>> taskClass;\n        private final Class<? extends Function<ScheduledExecution, Uni<Void>>> asyncTaskClass;\n        private final boolean runOnVirtualThread;\n        private final Class<? extends SkipPredicate> skipPredicateClass;\n        private final boolean nonconcurrent;\n\n        @SuppressWarnings(\"unchecked\")\n        public SerializedExecutionMetadata(JobDetail jobDetail) {\n            ClassLoader tccl = Thread.currentThread().getContextClassLoader();\n            String taskClassStr = jobDetail.getJobDataMap().getString(EXECUTION_METADATA_TASK_CLASS);\n            try {\n                this.taskClass = taskClassStr != null\n                        ? (Class<? extends Consumer<ScheduledExecution>>) tccl.loadClass(taskClassStr)\n                        : null;\n            } catch (ClassNotFoundException e) {\n                throw new IllegalStateException(\"Cannot load task class: \" + taskClassStr);\n            }\n            String asyncTaskClassStr = jobDetail.getJobDataMap().getString(EXECUTION_METADATA_ASYNC_TASK_CLASS);\n            try {\n                this.asyncTaskClass = asyncTaskClassStr != null\n                        ? (Class<? extends Function<ScheduledExecution, Uni<Void>>>) tccl.loadClass(asyncTaskClassStr)\n                        : null;\n            } catch (ClassNotFoundException e) {\n                throw new IllegalStateException(\"Cannot load async task class: \" + taskClassStr);\n            }\n\n            String skipPredicateClassStr = jobDetail.getJobDataMap().getString(EXECUTION_METADATA_SKIP_PREDICATE_CLASS);\n            try {\n                this.skipPredicateClass = skipPredicateClassStr != null\n                        ? (Class<? extends SkipPredicate>) tccl.loadClass(skipPredicateClassStr)\n                        : null;\n            } catch (ClassNotFoundException e) {\n                throw new IllegalStateException(\"Cannot load skip predicate class: \" + taskClassStr);\n            }","sourceCodeStart":1274,"sourceCodeEnd":1310,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/quartz/runtime/src/main/java/io/quarkus/quartz/runtime/QuartzSchedulerImpl.java#L1274-L1310","documentation":"Quarkus stores the fully-qualified name of the task class (the Consumer<ScheduledExecution> implementing a @Scheduled method's body) in the Quartz JobDataMap so persistent job stores can survive restarts. When the job fires, the scheduler loads the class via the thread context classloader; a ClassNotFoundException is converted to 'Cannot load task class: <name>'.","triggerScenarios":"A job persisted in a JDBC/other persistent Quartz store references EXECUTION_METADATA_TASK_CLASS that cannot be loaded through TCCL at execution time.","commonSituations":"The scheduled method/class was renamed, moved packages, or deleted while old rows remain in the Quartz DB tables (QRTZ_JOB_DETAIL); running with a different classloader setup (dev mode restarts, native image) than the one that stored the job; partially deployed artifacts missing the class.","solutions":["Delete stale job rows for the old class from the Quartz database tables (QRTZ_JOB_DETAILS, QRTZ_TRIGGERS) or change quarkus.quartz.store-type so jobs are rebuilt from code","Restore/redeploy the class or revert the rename/move so the stored FQCN resolves again","Inspect the stored task class name in the JobDataMap and compare it with classes actually on the classpath","Clear the Quartz tables entirely if the store should be rebuilt from @Scheduled annotations on next start"],"exampleFix":"// before (class renamed but DB still holds old FQCN)\npackage com.acme.sched; public class OldJob implements Consumer<ScheduledExecution> {...}\n// after\npackage com.acme.sched; public class RenamedJob implements Consumer<ScheduledExecution> {...}\n// plus: DELETE FROM QRTZ_JOB_DETAILS WHERE JOB_CLASS_NAME LIKE '%OldJob%';","handlingStrategy":"validation","validationCode":"// Before starting against a persistent store, verify stored job classes resolve\nString stored = jobDetail.getJobDataMap().getString(\"io.quarkus.quartz.task_class\");\nif (stored != null) {\n    try { Class.forName(stored, false, Thread.currentThread().getContextClassLoader()); }\n    catch (ClassNotFoundException e) { /* purge stale QRTZ rows before start */ }\n}","typeGuard":null,"tryCatchPattern":"try {\n    job.execute(executionContext);\n} catch (IllegalStateException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Cannot load task class\")) {\n        // rebuild job store from code: purge QRTZ_JOB_DETAILS rows and restart\n    }\n    throw e;\n}","preventionTips":["When renaming/moving @Scheduled classes, purge Quartz DB tables or bump store config","Prefer memory store in environments rebuilt from code each deploy","Keep the class FQCN stable once jobs are persisted in a JDBC store","Verify class presence in native-image if running native"],"tags":["quarkus","quartz","classpath","classnotfound","persistent-job-store"],"backgroundTag":"classnotfound-stale-job-store","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"}