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
- Configure exactly one task style: keep setTask OR setAsyncTask, not both
- Remove the earlier setAsyncTask call from the builder chain
- If both behaviors are needed, combine them inside a single task implementation
- 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
- Configure only one of setTask/setAsyncTask per JobDefinition
- Review builder chains for duplicate task setters
- Create a new JobDefinition for differently-configured jobs
- Centralize job creation in one factory method that enforces a single task style
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
- Sync task was already set
- Cannot modify a job that was already scheduled
- Scheduler implementation not available:
- A generic type is not allowed here; try creating a subclass
- Build item class must be leaf (final) types: %s
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/3d1102cb4b8afcb6.
Report an issue: GitHub.