flowable/flowable-engine · error · FlowableException
has no job handler type in job config for engine:
Error message
has no job handler type in job config for engine:
What it means
executeJobHandler requires every JobEntity to carry a jobHandlerType string that selects its JobHandler. When the entity's jobHandlerType is null, Flowable throws this FlowableException stating the job has no handler type. Without the type the engine cannot know what code to run for the job.
Solutions
- Always set the job handler type when creating jobs: jobEntity.setJobHandlerType("async-continuation") (or the appropriate type).
- Fix existing rows by updating JOB_HANDLER_TYPE for the offending job, or delete the orphan job row.
- If migrating jobs between environments, include the handler-type columns in the migration script.
- Add a pre-save validation that jobHandlerType is non-null for all created job entities.
Example fix
// before
MessageJobEntity job = jobService.createMessageJob();
job.setJobHandlerConfiguration("cfg");
// jobHandlerType never set
// after
MessageJobEntity job = jobService.createMessageJob();
job.setJobHandlerType(AsyncContinuationJobHandler.TYPE); // e.g. "async-continuation"
job.setJobHandlerConfiguration("cfg"); Defensive patterns
Strategy: validation
Validate before calling
if (job.getJobHandlerType() == null || job.getJobHandlerType().isEmpty()) {
throw new IllegalStateException("Job " + job.getId() + " has no jobHandlerType");
} Type guard
boolean hasHandlerType(JobEntity job) { return job.getJobHandlerType() != null && !job.getJobHandlerType().isEmpty(); } Try / catch
try { jobManager.executeMessageJob(job); } catch (FlowableException e) { if (e.getMessage().endsWith("has no job handler type")) { repairOrDeleteJobRow(job.getId()); } else throw e; } Prevention
- Set setJobHandlerType() whenever creating jobs programmatically.
- Include JOB_HANDLER_TYPE in any job-table migration scripts.
- Run a startup query flagging ACT_RU_JOB rows with NULL JOB_HANDLER_TYPE.
When it happens
Trigger: A JobEntity row (e.g. in ACT_RU_JOB) with NULL JOB_HANDLER_TYPE is passed to executeMessageJob/executeTimerJob -> executeJobHandler.
Common situations: Rows hand-inserted or migrated into the job tables without JOB_HANDLER_TYPE; custom job creation code that forgets setJobHandlerType(); data corruption or schema mismatches after upgrades.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Async
- Cannot get process definition for id for
- Invalid usage of async_activate job handler, variable scope…
- Invalid usage of job handler, variable scope is of type
- No history job handler registered for type
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/3a43ef59b1a747b7.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/asyncexecutor/DefaultJobManager.java:566
Map<String, JobHandler> jobHandlers = jobServiceConfiguration.getJobHandlers();
if (jobEntity.getJobHandlerType() != null) {
if (jobHandlers != null) {
JobHandler jobHandler = jobHandlers.get(jobEntity.getJobHandlerType());
if (jobHandler != null) {
jobHandler.execute(jobEntity, jobEntity.getJobHandlerConfiguration(), variableScope, getCommandContext());
} else {
throw new FlowableException("No job handler registered for type " + jobEntity.getJobHandlerType() +
" in job config for engine: " + jobServiceConfiguration.getEngineName() + " for " + jobEntity);
}
} else {
throw new FlowableException("No job handler registered for type " + jobEntity.getJobHandlerType() +
" in job config for engine: " + jobServiceConfiguration.getEngineName() + " for " + jobEntity);
}
} else {
throw new FlowableException(jobEntity + " has no job handler type in job config for engine: " + jobServiceConfiguration.getEngineName());
}
}
protected void executeHistoryJobHandler(HistoryJobEntity historyJobEntity) {
Map<String, HistoryJobHandler> jobHandlers = jobServiceConfiguration.getHistoryJobHandlers();
if (historyJobEntity.getJobHandlerType() != null) {
if (jobHandlers != null) {
HistoryJobHandler jobHandler = jobHandlers.get(historyJobEntity.getJobHandlerType());
if (jobHandler != null) {
jobHandler.execute(historyJobEntity, historyJobEntity.getJobHandlerConfiguration(), getCommandContext(), jobServiceConfiguration);
} else {
throw new FlowableException("No history job handler registered for type " + historyJobEntity.getJobHandlerType() +
" in job config for engine: " + jobServiceConfiguration.getEngineName() + " for " + historyJobEntity);
}
} else {
throw new FlowableException("No history job handler registered for type " + historyJobEntity.getJobHandlerType() +
" in job config for engine: " + jobServiceConfiguration.getEngineName() + " for " + historyJobEntity);View on GitHub (pinned to d6d39ce1c6)