flowable/flowable-engine · error · FlowableException
Only jobs with type JobEntity are supported to be executed…
Error message
Only jobs with type JobEntity are supported to be executed. It was
What it means
DefaultJobManager.execute(Job) only knows how to execute JobEntity instances. If the async executor hands it a JobInfo (or any other non-JobEntity job implementation) it cannot be cast to a message or timer JobEntity, so Flowable throws this FlowableException. It is an internal contract violation between the async executor's job acquisition and the job manager.
Solutions
- Ensure the object passed to jobManager.execute(job) is a JobEntity instance (e.g. the loaded MessageJobEntity/TimerJobEntity), not a JobInfo wrapper.
- If using a custom async executor, fetch the actual JobEntity from the job entity manager before calling execute().
- Check Flowable version compatibility between the engine and any custom async-executor integration code.
Example fix
// before jobInfo = acquireJob(); jobManager.execute(jobInfo); // JobInfo, not JobEntity // after JobEntity jobEntity = jobEntityManager.findById(jobInfo.getId()); jobManager.execute(jobEntity);
Defensive patterns
Strategy: type-guard
Validate before calling
if (!(job instanceof JobEntity)) { throw new IllegalArgumentException("execute() requires a JobEntity, got: " + job.getClass()); }
jobManager.execute((JobEntity) job); Type guard
boolean isExecutableJob(Job job) { return job instanceof JobEntity; } Try / catch
try { jobManager.execute(job); } catch (FlowableException e) { if (e.getMessage().startsWith("Only jobs with type JobEntity")) { JobEntity entity = jobEntityManager.findById(job.getId()); jobManager.execute(entity); } else throw e; } Prevention
- Never pass JobInfo wrappers directly into DefaultJobManager.execute.
- Resolve the underlying JobEntity via the job entity manager first.
- Unit-test custom async executors with real JobEntity instances.
When it happens
Trigger: Calling DefaultJobManager.execute(Job) with a Job implementation that is not a JobEntity (e.g. a custom JobInfo implementation passed directly, or a custom async executor feeding non-entity jobs).
Common situations: Custom async executor implementations or test harnesses that wrap jobs in a JobInfo facade and pass the wrapper instead of the underlying JobEntity; upgrading Flowable versions where job interfaces changed.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- App resource is not of type AppModel
- Can only move a history job to a history job
- Can only use a collection of String elements for…
- Cannot convert event payload
- Cannot convert event payload
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/c41d27099acd90be.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/asyncexecutor/DefaultJobManager.java:337
return historyJobEntity;
}
@Override
public void execute(JobInfo job) {
if (job instanceof HistoryJobEntity) {
callHistoryJobProcessors(HistoryJobProcessorContext.Phase.BEFORE_EXECUTE, (HistoryJobEntity) job);
executeHistoryJob((HistoryJobEntity) job);
} else if (job instanceof JobEntity) {
callJobProcessors(JobProcessorContext.Phase.BEFORE_EXECUTE, (JobEntity) job);
if (Job.JOB_TYPE_MESSAGE.equals(((Job) job).getJobType())) {
executeMessageJob((JobEntity) job);
} else if (Job.JOB_TYPE_TIMER.equals(((Job) job).getJobType())) {
executeTimerJob((JobEntity) job);
}
} else {
throw new FlowableException("Only jobs with type JobEntity are supported to be executed. It was " + job);
}
}
@Override
public void unacquire(JobInfo job) {
if (job instanceof HistoryJob) {
HistoryJobEntity jobEntity = jobServiceConfiguration.getHistoryJobEntityManager().findById(job.getId());
if (jobEntity == null) {
LOGGER.debug("History Job {} does not exist anymore and will not be unacquired. It has most likely been deleted "
+ "e.g. as part of another concurrent part of a process / case instance.", job.getId());
return;
}
jobEntity.setLockExpirationTime(null);
jobEntity.setLockOwner(null);
View on GitHub (pinned to d6d39ce1c6)