quarkusio/quarkus · error · IllegalStateException

A job with this identity is already scheduled: {identity}

Error message

A job with this identity is already scheduled: {identity}

What it means

Quarkus Scheduler allows only one task per identity. When scheduling programmatically, `scheduledTasks.putIfAbsent` reveals that an identity is already registered, so an IllegalStateException naming the identity is thrown to prevent duplicate jobs.

Source

Thrown at extensions/quartz/runtime/src/main/java/io/quarkus/quartz/runtime/QuartzSchedulerImpl.java:1051

                vertx, task != null && runtimeConfig.runBlockingScheduledMethodOnQuartzThread(),
                SchedulerUtils.parseExecutionMaxDelayAsMillis(scheduled), blockingExecutor);
        QuartzTrigger quartzTrigger = new QuartzTrigger(trigger.getKey(),
                new Function<>() {
                    @Override
                    public org.quartz.Trigger apply(TriggerKey triggerKey) {
                        try {
                            return scheduler.getTrigger(triggerKey);
                        } catch (SchedulerException e) {
                            throw new IllegalStateException(e);
                        }
                    }
                }, invoker,
                SchedulerUtils.parseOverdueGracePeriod(scheduled, defaultOverdueGracePeriod),
                runtimeConfig.runBlockingScheduledMethodOnQuartzThread(), true, null, description);
        QuartzTrigger existing = scheduledTasks.putIfAbsent(scheduled.identity(), quartzTrigger);

        if (existing != null) {
            throw new IllegalStateException("A job with this identity is already scheduled: " + scheduled.identity());
        }

        try {
            if (oldTrigger != null) {
                scheduler.rescheduleJob(trigger.getKey(), trigger);
                LOGGER.debugf("Rescheduled job definition with config %s", scheduled);
            } else {
                scheduler.scheduleJob(jobDetail, trigger);
                LOGGER.debugf("Scheduled job definition with config %s", scheduled);
            }
        } catch (SchedulerException e) {
            throw new IllegalStateException(e);
        }
        return quartzTrigger;
    }

    /**
     * @see Nonconcurrent

View on GitHub (pinned to e1c734241f)

Solutions

  1. Use a unique identity per schedule, or check `scheduler.getScheduledJobs()`/unwrap existing QuartzTrigger before scheduling
  2. Make scheduling idempotent: skip when the identity already exists instead of calling schedule again
  3. Rename one of the conflicting @Scheduled identities (annotation and programmatic identity must not collide)

Example fix

// before
scheduler.newJob("sync").setEvery("10m").setTask(t -> sync()).schedule(); // second call throws
// after
if (scheduler.getJobByIdentity("sync").isEmpty()) {
    scheduler.newJob("sync").setEvery("10m").setTask(t -> sync()).schedule();
}
Defensive patterns

Strategy: try-catch

Validate before calling

boolean taken = scheduler.getScheduledJobs().stream()
    .anyMatch(j -> j.getSchedule().identity().equals("myJob"));
if (taken) { /* skip or unschedule first */ }

Try / catch

try {
    scheduler.newJob("myJob").setEvery("10m").setTask(t -> run()).schedule();
} catch (IllegalStateException e) {
    if (e.getMessage().contains("already scheduled")) { /* skip duplicate registration */ }
}

Prevention

When it happens

Trigger: Calling `scheduler.newJob("sameId")...schedule()` twice, or scheduling programmatically an identity already defined by a @Scheduled annotation on a bean.

Common situations: Application restart code paths re-registering jobs idempotently; duplicate @Scheduled identity values across beans; test code scheduling the same identity repeatedly within one application instance.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/066201d7b38294de. Report an issue: GitHub.