quarkusio/quarkus · error · IllegalStateException
Non-static @Scheduled methods may not be declared on abstrac
Error message
Non-static @Scheduled methods may not be declared on abstract classes and interfaces: %s() declared on %s
What it means
@Scheduled methods must be either static or declared on a concrete (non-abstract, non-interface) class so the scheduler can instantiate/invoke them. During index scanning, collectScheduledMethods rejects non-static methods found on abstract classes or interfaces at build time.
Source
Thrown at extensions/scheduler/deployment/src/main/java/io/quarkus/scheduler/deployment/SchedulerProcessor.java:204
Map<MethodInfo, List<AnnotationInstance>> staticScheduledMethods = new HashMap<>();
List<AnnotationInstance> schedules = new ArrayList<>(
beanArchives.getIndex().getAnnotations(SchedulerDotNames.SCHEDULED_NAME));
for (AnnotationInstance annotationInstance : beanArchives.getIndex().getAnnotations(SchedulerDotNames.SCHEDULES_NAME)) {
for (AnnotationInstance scheduledInstance : annotationInstance.value().asNestedArray()) {
// We need to set the target of the containing instance
schedules.add(AnnotationInstance.create(scheduledInstance.name(), annotationInstance.target(),
scheduledInstance.values()));
}
}
for (AnnotationInstance annotationInstance : schedules) {
if (annotationInstance.target().kind() != METHOD) {
continue; // This should never happen as the annotation has @Target(METHOD)
}
MethodInfo method = annotationInstance.target().asMethod();
ClassInfo declaringClass = method.declaringClass();
if (!Modifier.isStatic(method.flags())
&& (Modifier.isAbstract(declaringClass.flags()) || declaringClass.isInterface())) {
throw new IllegalStateException(String.format(
"Non-static @Scheduled methods may not be declared on abstract classes and interfaces: %s() declared on %s",
method.name(), declaringClass.name()));
}
if (Modifier.isStatic(method.flags()) && !KotlinUtil.isSuspendMethod(method)) {
List<AnnotationInstance> methodSchedules = staticScheduledMethods.get(method);
if (methodSchedules == null) {
methodSchedules = new ArrayList<>();
staticScheduledMethods.put(method, methodSchedules);
}
methodSchedules.add(annotationInstance);
}
}
for (Entry<MethodInfo, List<AnnotationInstance>> e : staticScheduledMethods.entrySet()) {
MethodInfo method = e.getKey();
scheduledBusinessMethods.produce(new ScheduledBusinessMethodItem(null, method, e.getValue(),
transformedAnnotations.hasAnnotation(method, SchedulerDotNames.NON_BLOCKING),
transformedAnnotations.hasAnnotation(method, SchedulerDotNames.RUN_ON_VIRTUAL_THREAD)));View on GitHub (pinned to e1c734241f)
Solutions
- Move the @Scheduled method to a concrete class with a CDI scope
- Make the method static if it must live on an abstract type
- Remove @Scheduled from interfaces; schedule in concrete implementations instead
- Have each concrete subclass declare its own @Scheduled method
Example fix
// before
public interface Jobs {
@Scheduled(every = "10s")
void run(); // non-static on interface
}
// after
@ApplicationScoped
public class Jobs {
@Scheduled(every = "10s")
void run() { ... }
} Defensive patterns
Strategy: validation
Validate before calling
static boolean isLegalScheduledMethod(Method m) {
int cls = m.getDeclaringClass().getModifiers();
return java.lang.reflect.Modifier.isStatic(m.getModifiers())
|| (!java.lang.reflect.Modifier.isAbstract(cls) && !m.getDeclaringClass().isInterface());
} Prevention
- Put @Scheduled only on concrete, CDI-scoped classes
- Use static scheduled methods for abstract holders
- Never place @Scheduled on interface methods
- Review scheduled classes when refactoring into hierarchies
When it happens
Trigger: Declaring a non-static @Scheduled method inside an interface or an abstract class that is not overridden by a concrete bean at build time.
Common situations: Putting scheduled job signatures in a shared interface expecting subclasses to inherit scheduling; base abstract class with a @Scheduled template method; refactoring a concrete scheduled class into an abstract hierarchy.
Related errors
- Value not set for ${param}
- Something went wrong during parameter type resolution - expe
- Invalid scheduler implementations detected:
- Class '%s' is annotated with '%s' and '%s' security annotati
- AnnotationInstance ${instance} is an invalid target. Only Cl
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/66ab1c54e9f18f0d.
Report an issue: GitHub.