quarkusio/quarkus · error · IllegalStateException
A skipPredicate instance may not be serialized
Error message
A skipPredicate instance may not be serialized
What it means
SyntheticScheduled is the serializable description of a programmatically created @Scheduled method; toJson() flattens it to JSON for the build-time/CDI synthetic bean machinery. A skipPredicate configured as a live object instance cannot be represented in JSON, so toJson() throws this IllegalStateException if one is present.
Source
Thrown at extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/SyntheticScheduled.java:114
@Override
public String executeWith() {
return implementation;
}
@Override
public String executionMaxDelay() {
return executionMaxDelay;
}
@Override
public String description() {
return description;
}
public String toJson() {
if (skipPredicate != null) {
throw new IllegalStateException("A skipPredicate instance may not be serialized");
}
JsonObject json = new JsonObject();
json.put("identity", identity);
json.put("cron", cron);
json.put("every", every);
json.put("delay", delay);
json.put("delayUnit", delayUnit.toString());
json.put("delayed", delayed);
json.put("overdueGracePeriod", overdueGracePeriod);
json.put("concurrentExecution", concurrentExecution.toString());
json.put("timeZone", timeZone);
json.put("executeWith", implementation);
json.put("executionMaxDelay", executionMaxDelay);
json.put("description", description);
return json.encode();
}
public static SyntheticScheduled fromJson(String json) {View on GitHub (pinned to e1c734241f)
Solutions
- Configure the skip predicate as a Class (setSkipPredicate(Class)) so the JSON can reference it by name instead of an instance
- Avoid serializing SyntheticScheduled with instance-based predicates; register the predicate as a CDI bean and reference its class
- If persistence of job metadata is required, ensure predicates are class-referenced before toJson() is invoked
Example fix
// before jobDef.setSkipPredicate(new MySkipPredicate()); // instance -> not serializable // after jobDef.setSkipPredicate(MySkipPredicate.class);
Defensive patterns
Strategy: validation
Validate before calling
if (synthetic != null && syntheticHasInstanceSkipPredicate(synthetic)) {
throw new IllegalStateException("use setSkipPredicate(Class) for serializable schedules");
} Type guard
boolean serializableSchedule(SyntheticScheduled s) {
return s.skipPredicateClass() != null; // class-referenced predicate, not an instance
} Try / catch
try {
json = synthetic.toJson();
} catch (IllegalStateException e) {
LOG.error("Schedule uses an instance skipPredicate; switch to a Class reference", e);
} Prevention
- Always configure skip predicates via Class references, not instances/lambdas
- Register predicates as CDI beans and reference their classes
- Avoid serializing synthetic schedules that hold live objects
- Keep predicate classes no-arg constructible for later instantiation
When it happens
Trigger: Serializing a SyntheticScheduled whose skipPredicate field is a non-null instance, i.e. a job definition built with setSkipPredicate(instance) rather than a class name, then having its metadata converted to JSON (e.g. recorded synthetic bean output).
Common situations: Using a Lambda or prebuilt SkipPredicate object in a programmatically scheduled job and then serializing the schedule (Quartz job-store persistence or build-time recording); moving from skip predicate classes to instances across versions.
Related errors
- Failed to record call to method ${call.method}
- Failed to substitute ${param}
- Cannot serialise field '${i.getName()}' on object '${param}'
- Couldn't load object of type ${i.propertyType.getName()} for
- Cannot create new DeferredArrayStoreParameter after array ha
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/6dc270a02884f9a5.
Report an issue: GitHub.