{"record":{"id":"874c96a41e947e8b","repo":"quarkusio/quarkus","slug":"cannot-load-skip-predicate-class-taskclass","errorCode":null,"errorMessage":"Cannot load skip predicate class: {taskClass}","messagePattern":"Cannot load skip predicate class: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"extensions/quartz/runtime/src/main/java/io/quarkus/quartz/runtime/QuartzSchedulerImpl.java","lineNumber":1309,"sourceCode":"            } 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            }\n            this.runOnVirtualThread = Boolean\n                    .parseBoolean(jobDetail.getJobDataMap().getString(EXECUTION_METADATA_RUN_ON_VIRTUAL_THREAD));\n            this.nonconcurrent = Boolean.parseBoolean(jobDetail.getJobDataMap().getString(EXECUTION_METADATA_NONCONCURRENT));\n        }\n\n        @Override\n        public Consumer<ScheduledExecution> task() {\n            return taskClass != null ? SchedulerUtils.instantiateBeanOrClass(taskClass) : null;\n        }\n\n        @Override\n        public Class<? extends Consumer<ScheduledExecution>> taskClass() {\n            return taskClass;\n        }\n\n        @Override\n        public Function<ScheduledExecution, Uni<Void>> asyncTask() {","sourceCodeStart":1291,"sourceCodeEnd":1327,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/quartz/runtime/src/main/java/io/quarkus/quartz/runtime/QuartzSchedulerImpl.java#L1291-L1327","documentation":"Quartz jobs persisted in a store also carry the SkipPredicate class FQCN (used to decide whether a run should be skipped, e.g. @SkipPredicate). When the job executes, QuartzSchedulerImpl loads this class via TCCL and throws 'Cannot load skip predicate class: <name>' on ClassNotFoundException. The message interpolates the wrong variable (taskClassStr), so verify the actual EXECUTION_METADATA_SKIP_PREDICATE_CLASS value in the JobDataMap.","triggerScenarios":"A @Scheduled method with a custom SkipPredicate was persisted to a Quartz job store; at execution time the stored EXECUTION_METADATA_SKIP_PREDICATE_CLASS FQCN can no longer be loaded by the TCCL.","commonSituations":"SkipPredicate implementation renamed, moved to another package, or deleted while its jobs remain in the JDBC Quartz store; native image not including the predicate class; stale rows from a previous application version.","solutions":["Delete stale Quartz job rows whose JobDataMap references the removed/renamed SkipPredicate and restart so Quarkus re-registers jobs from code","Restore the SkipPredicate class or revert the rename/move so the stored FQCN resolves","Check the EXECUTION_METADATA_SKIP_PREDICATE_CLASS JobDataMap entry for the exact class name (the message text may show the wrong name due to a bug)","Ensure the predicate class is registered for native-image if running a native build"],"exampleFix":"// before: predicate deleted while persisted jobs still reference it\n// com.acme.OldSkipPredicate (removed)\n// after: purge the rows and restart so Quarkus rebuilds job metadata from @SkipPredicate\n// SQL: DELETE FROM QRTZ_JOB_DETAILS WHERE JOB_NAME = 'com.acme.OldSkipPredicate';","handlingStrategy":"validation","validationCode":"// Validate the skip predicate FQCN stored on the job resolves\nString skip = jobDetail.getJobDataMap().getString(\"io.quarkus.quartz.skip_predicate_class\");\nif (skip != null) {\n    try { Class.forName(skip, false, Thread.currentThread().getContextClassLoader()); }\n    catch (ClassNotFoundException e) { /* purge the stale job row before it fires */ }\n}","typeGuard":null,"tryCatchPattern":"try {\n    fireJob();\n} catch (IllegalStateException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Cannot load skip predicate class\")) {\n        LOG.error(\"Stored SkipPredicate class missing from classpath\");\n    }\n    throw e;\n}","preventionTips":["Keep @SkipPredicate implementations in stable packages","Purge persisted Quartz jobs after deleting predicates","Register predicate classes for native-image reflection when needed","Diff stored JobDataMap class names against the current codebase after upgrades"],"tags":["quarkus","quartz","classpath","classnotfound","skip-predicate","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-14T00:17:10.932Z"}