flowable/flowable-engine · error · FlowableException

No job handler registered for type

Error message

No job handler registered for type 

What it means

executeJobHandler looks up the job's handler type in the engine's registered JobHandler map. When the map is populated but the specific jobEntity.getJobHandlerType() has no matching handler, Flowable throws this FlowableException naming the type and engine. Every job created must have a handler registered in the process engine configuration.

Solutions

  1. Register the missing handler: add it to the process engine configuration (ProcessEngineConfigurationImpl.setCustomJobHandlers or the job service configuration's job handler map).
  2. Verify the jobHandlerType string stored on the job row against the keys of the registered jobHandlers map.
  3. Align engine versions if jobs were created by a different Flowable version (check ACT_RU_JOB JOB_HANDLER_TYPE values).
  4. Check for errors in engine bootstrap logs indicating handler registration failures.

Example fix

// before
ProcessEngineConfiguration cfg = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("flowable.cfg.xml");
// custom handler never registered

// after
ProcessEngineConfigurationImpl cfg = (ProcessEngineConfigurationImpl)
    ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("flowable.cfg.xml");
List<JobHandler> handlers = new ArrayList<>();
handlers.add(new MyCustomJobHandler());
cfg.setCustomJobHandlers(handlers);
Defensive patterns

Strategy: validation

Validate before calling

Map<String, JobHandler> handlers = jobServiceConfiguration.getJobHandlers();
if (handlers == null || !handlers.containsKey(job.getJobHandlerType())) {
    throw new IllegalStateException("Unregistered job handler type: " + job.getJobHandlerType());
}

Try / catch

try { jobManager.executeMessageJob(job); } catch (FlowableException e) { if (e.getMessage().startsWith("No job handler registered")) { registerMissingHandlerAndRetry(job); } else throw e; }

Prevention

When it happens

Trigger: A JobEntity with a jobHandlerType (e.g. 'async-continuation', 'timer', custom handler) that is not present in the JobServiceConfiguration's jobHandlers map when executeMessageJob or executeTimerJob runs the job.

Common situations: Custom JobHandler implementations not registered via the engine configuration's customJobHandlers; jobs persisted by a newer/other Flowable version whose handler types the current engine does not know; classpath issues dropping handler registrations.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/1a421566919d2535. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/asyncexecutor/DefaultJobManager.java:556

    protected void executeJobHandler(JobEntity jobEntity) {
        VariableScope variableScope = null;
        if (jobServiceConfiguration.getInternalJobManager() != null) {
            variableScope = jobServiceConfiguration.getInternalJobManager().resolveVariableScope(jobEntity);
        }
        
        if (variableScope == null) {
            variableScope = NoExecutionVariableScope.getSharedInstance();
        }

        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());

View on GitHub (pinned to d6d39ce1c6)