quarkusio/quarkus · error · IllegalStateException

Unable to unschedule job with identity: ${identity}

Error message

Unable to unschedule job with identity: ${identity}

What it means

Quarkus throws this IllegalStateException from Scheduler.unscheduleJob(identity) when the underlying Quartz scheduler.unscheduleJob(triggerKey) fails with a SchedulerException. Note the original cause is dropped (not chained). Only programmatic jobs (created via newJob()) can be unscheduled this way; static @Scheduled jobs return null.

Source

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

        }
        return new QuartzJobDefinitionImpl(identity);
    }

    @Override
    public Trigger unscheduleJob(String identity) {
        if (!isStarted()) {
            throw notStarted();
        }
        Objects.requireNonNull(identity);
        if (!identity.isEmpty()) {
            String parsedIdentity = SchedulerUtils.lookUpPropertyValue(identity);
            QuartzTrigger trigger = scheduledTasks.get(parsedIdentity);
            if (trigger != null && trigger.isProgrammatic) {
                if (scheduledTasks.remove(identity) != null) {
                    try {
                        scheduler.unscheduleJob(trigger.triggerKey);
                    } catch (SchedulerException e) {
                        throw new IllegalStateException("Unable to unschedule job with identity: " + identity);
                    }
                    return trigger;
                }
            }
        }
        return null;
    }

    // Use Interceptor.Priority.PLATFORM_BEFORE to start the scheduler before regular StartupEvent observers
    void start(@Observes @Priority(Interceptor.Priority.PLATFORM_BEFORE) StartupEvent startupEvent) {
        if (scheduler == null || startHalted) {
            return;
        }
        try {
            scheduler.start();
        } catch (SchedulerException e) {
            throw new IllegalStateException("Unable to start Scheduler", e);
        }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Verify datasource connectivity when using the jdbc store
  2. Confirm the job is programmatic (unscheduleJob returns null for @Scheduled-annotated jobs)
  3. Check whether the trigger was already removed (idempotent handling of the identity)
  4. Retry the unschedule; the removed entry is already dropped from the in-memory map so state may need reconciliation

Example fix

// before
Trigger t = scheduler.unscheduleJob("myJob");
// after
Trigger t = scheduler.getScheduledJob("myJob");
if (t != null) {
    try {
        scheduler.unscheduleJob("myJob");
    } catch (IllegalStateException e) {
        LOGGER.warnf("Unschedule failed for myJob: %s", e.getMessage());
    }
}
Defensive patterns

Strategy: validation

Validate before calling

Trigger t = scheduler.getScheduledJob(identity);
if (t == null) return; // nothing to unschedule

Try / catch

try {
    scheduler.unscheduleJob(identity);
} catch (IllegalStateException e) {
    LOGGER.warnf("Unschedule failed for %s; trigger may already be gone", identity);
}

Prevention

When it happens

Trigger: Calling Scheduler.unscheduleJob(identity) for an existing programmatic job whose trigger cannot be removed — e.g. JDBC JobStore DB failure, clustered store lock contention, or the trigger no longer existing in the store.

Common situations: Database-backed store unreachable; job's trigger was removed externally (another node, manual DB edit); calling for a static @Scheduled job identity silently returns null instead; race with concurrent unscheduleJob calls.

Related errors


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