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'.
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)
Solutions
- Remove the redundant setTask call so only setAsyncTask remains
- Pick one execution style per job definition
- Instantiate a new JobDefinition if you need a differently configured job
- 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
- Pick one execution style (sync Consumer vs async Uni function) per job
- When migrating sync->async, delete the old setTask call
- Keep job definitions short-lived and single-purpose
- Add a code-review checklist item for duplicate builder setters
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
- Async 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/bbbdb287c88cb8bb.
Report an issue: GitHub.