{"record":{"id":"4fb3efb9a4ed1b5d","repo":"quarkusio/quarkus","slug":"unable-to-obtain-the-job-detail-for-triggerkey","errorCode":null,"errorMessage":"Unable to obtain the job detail for ${triggerKey}","messagePattern":"Unable to obtain the job detail for (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"extensions/quartz/runtime/src/main/java/io/quarkus/quartz/runtime/QuartzSchedulerImpl.java","lineNumber":289,"sourceCode":"                                            SchedulerUtils.parseOverdueGracePeriod(scheduled, defaultOverdueGracePeriod),\n                                            quartzSupport.getRuntimeConfig().runBlockingScheduledMethodOnQuartzThread(), false,\n                                            method.getMethodDescription(), description));\n                        } else {\n                            // The job is disabled\n                            scheduler.deleteJob(new JobKey(identity, Scheduler.class.getName()));\n                        }\n                    }\n                }\n\n                // Find persistent jobs scheduled with JobDefinition\n                if (storeType.isDbStore()) {\n                    Set<TriggerKey> triggers = scheduler\n                            .getTriggerKeys(GroupMatcher.triggerGroupEquals(Scheduler.class.getName()));\n\n                    for (TriggerKey triggerKey : triggers) {\n                        JobDetail jobDetail = scheduler.getJobDetail(new JobKey(triggerKey.getName(), triggerKey.getGroup()));\n                        if (jobDetail == null) {\n                            throw new IllegalStateException(\"Unable to obtain the job detail for \" + triggerKey);\n                        }\n\n                        String scheduledJson = jobDetail.getJobDataMap().getString(SCHEDULED_METADATA);\n                        if (scheduledJson != null) {\n                            SyntheticScheduled scheduled = SyntheticScheduled.fromJson(scheduledJson);\n                            org.quartz.Trigger oldTrigger = scheduler.getTrigger(triggerKey);\n                            if (oldTrigger == null) {\n                                throw new IllegalStateException(\"Unable to obtain the trigger for \" + triggerKey);\n                            }\n                            createJobDefinitionQuartzTrigger(new SerializedExecutionMetadata(jobDetail), scheduled, oldTrigger);\n                        }\n                    }\n                }\n\n                if (transaction != null) {\n                    transaction.commit();\n                }\n            } catch (Throwable e) {","sourceCodeStart":271,"sourceCodeEnd":307,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/quartz/runtime/src/main/java/io/quarkus/quartz/runtime/QuartzSchedulerImpl.java#L271-L307","documentation":"On startup with a persistent Quartz store, QuartzSchedulerImpl re-schedules synthetic @Scheduled triggers by looking up each stored trigger's JobDetail via scheduler.getJobDetail(). If the JobDetail is missing (null) while a trigger exists, IllegalStateException 'Unable to obtain the job detail for <triggerKey>' is thrown — the scheduler store is inconsistent.","triggerScenarios":"Trigger rows exist in the JDBC (or other persistent) QRTZ_TRIGGERS table but corresponding QRTZ_JOB_DETAILS rows are missing/corrupted — e.g. jobs were removed from another scheduler instance sharing the store, manual DB cleanup, or interrupted schema changes.","commonSituations":"Multiple apps sharing one Quartz JDBC store with the same scheduler name; manual truncation of QRTZ_JOB_DETAILS; upgrading while old triggers persist; store corruption after crash.","solutions":["Clean the orphaned trigger rows: delete the trigger (or the scheduler group) from the Quartz tables, or wipe Quartz tables and let Quarkus re-schedule.","Ensure all application instances sharing the store use the same quarkus.quartz.scheduler-name and compatible versions.","Restore schema consistency from backup or re-create the store schema.","Check for other clients (scripts, other schedulers) mutating the Quartz tables."],"exampleFix":"-- remove orphaned triggers so Quarkus re-creates them\nDELETE FROM QRTZ_TRIGGERS WHERE SCHED_NAME = 'quarkusQuartzScheduler';\nDELETE FROM QRTZ_CRON_TRIGGERS WHERE SCHED_NAME = 'quarkusQuartzScheduler';","handlingStrategy":"validation","validationCode":"// startup health check on a JDBC store: every trigger must have a job detail\nfor (TriggerKey key : scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(Scheduler.class.getName()))) {\n    if (scheduler.getJobDetail(new JobKey(key.getName(), key.getGroup())) == null) {\n        log.error(\"Orphaned trigger in Quartz store: \" + key + \" — clean QRTZ_TRIGGERS or reset the store\");\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    scheduler.start();\n} catch (IllegalStateException e) {\n    if (e.getMessage().startsWith(\"Unable to obtain the job detail\")) {\n        // inconsistent store: clean Quartz tables and restart\n        throw new RuntimeException(\"Quartz store inconsistent — purge orphaned triggers\", e);\n    }\n    throw e;\n}","preventionTips":["Never manually delete rows from QRTZ_JOB_DETAILS without cleaning QRTZ_TRIGGERS.","Use one logical scheduler name per shared store; coordinate multi-app setups.","Take a DB backup before upgrading Quarkus/Quartz against a persistent store."],"tags":["quarkus","quartz","jdbc-store","data-inconsistency","startup"],"backgroundTag":"quartz-store-inconsistent-state","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"}