quarkusio/quarkus · error · IllegalStateException

Sync task was already set

Error message

Sync task was already set

What it means

AbstractJobDefinition.setAsyncTask() installs the async Uni-returning task for a job definition. Because a job may define only one task, this IllegalStateException is thrown when a synchronous task (setTask) was already set. It is the mirror guard of 'Async task was already set'.

Solutions

  1. Remove the redundant setTask call so only setAsyncTask remains
  2. Pick one execution style per job definition
  3. Instantiate a new JobDefinition if you need a differently configured job
  4. Search the builder chain for both setters and delete the obsolete one

Example fix

// before
scheduler.newJob("j").setTask(c).setAsyncTask(fn);
// after
scheduler.newJob("j").setAsyncTask(fn);
Defensive patterns

Strategy: validation

Validate before calling

if (syncTaskSet) {
    throw new IllegalStateException("task already set; remove setTask before setAsyncTask");
}
definition.setAsyncTask(fn);

Try / catch

try {
    definition.setAsyncTask(fn);
} catch (IllegalStateException e) {
    LOG.error("Job {} already has a sync task", name, e);
}

Prevention

When it happens

Trigger: Calling scheduler.newJob(...).setTask(consumer).setAsyncTask(fn) on the same definition; calling setAsyncTask(Class) overloads after setTask; reuse of a JobDefinition that already carries a sync task.

Common situations: Migrating a job from sync to async execution while keeping the old setTask call; framework wrappers that pre-set a sync task; accidental double-configuration in fluent chains.

Related errors


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

Appendix: source

Thrown at extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/AbstractJobDefinition.java:138

        if (asyncTask != null) {
            throw new IllegalStateException("Async task was already set");
        }
        this.task = Objects.requireNonNull(task);
        this.runOnVirtualThread = runOnVirtualThread;
        return self();
    }

    @Override
    public THIS setTask(Class<? extends Consumer<ScheduledExecution>> taskClass, boolean runOnVirtualThread) {
        this.taskClass = Objects.requireNonNull(taskClass);
        return setTask(SchedulerUtils.instantiateBeanOrClass(taskClass), runOnVirtualThread);
    }

    @Override
    public THIS setAsyncTask(Function<ScheduledExecution, Uni<Void>> asyncTask) {
        checkScheduled();
        if (task != null) {
            throw new IllegalStateException("Sync task was already set");
        }
        this.asyncTask = Objects.requireNonNull(asyncTask);
        return self();
    }

    @Override
    public THIS setAsyncTask(Class<? extends Function<ScheduledExecution, Uni<Void>>> asyncTaskClass) {
        this.asyncTaskClass = Objects.requireNonNull(asyncTaskClass);
        return setAsyncTask(SchedulerUtils.instantiateBeanOrClass(asyncTaskClass));
    }

    protected void checkScheduled() {
        if (scheduled) {
            throw new IllegalStateException("Cannot modify a job that was already scheduled");
        }
    }

    @SuppressWarnings("unchecked")

View on GitHub (pinned to e1c734241f)