quarkusio/quarkus · error · IllegalStateException

Async task was already set

Error message

Async task was already set

What it means

AbstractJobDefinition.setTask() installs the synchronous task Consumer for a programmatically defined job. A job definition accepts either a sync task or an async task, but not both; if an async task (setAsyncTask) was already set, this IllegalStateException is thrown. It enforces mutual exclusivity of the two task styles.

Source

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

    @Override
    public THIS setExecutionMaxDelay(String maxDelay) {
        checkScheduled();
        this.executionMaxDelay = maxDelay;
        return self();
    }

    @Override
    public THIS setDescription(String description) {
        checkScheduled();
        this.description = Objects.requireNonNull(description);
        return self();
    }

    @Override
    public THIS setTask(Consumer<ScheduledExecution> task, boolean runOnVirtualThread) {
        checkScheduled();
        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");
        }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Configure exactly one task style: keep setTask OR setAsyncTask, not both
  2. Remove the earlier setAsyncTask call from the builder chain
  3. If both behaviors are needed, combine them inside a single task implementation
  4. Create a fresh JobDefinition via scheduler.newJob(...) instead of reusing a partially configured one

Example fix

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

Strategy: validation

Validate before calling

if (asyncTaskSet) {
    throw new IllegalStateException("choose either sync or async task");
}
definition.setTask(task);

Try / catch

try {
    definition.setTask(task);
} catch (IllegalStateException e) {
    LOG.error("Job {} already has an async task; drop the duplicate setter", name, e);
}

Prevention

When it happens

Trigger: Calling scheduler.newJob(...).setAsyncTask(fn).setTask(consumer) (or setTask after any setAsyncTask variant including Class-based overloads) on the same JobDefinition before scheduling.

Common situations: Copy-pasted builder chains where both task styles were configured; a shared base builder that sets an async task and calling code adding a sync one; refactoring from sync to async without removing the other call.

Related errors


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