{"record":{"id":"3a43ef59b1a747b7","repo":"flowable/flowable-engine","slug":"has-no-job-handler-type-in-job-config-for-engine","errorCode":null,"errorMessage":" has no job handler type in job config for engine: ","messagePattern":" has no job handler type in job config for engine: ","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/asyncexecutor/DefaultJobManager.java","lineNumber":566,"sourceCode":"        Map<String, JobHandler> jobHandlers = jobServiceConfiguration.getJobHandlers();\n        if (jobEntity.getJobHandlerType() != null) {\n            \n            if (jobHandlers != null) {\n                JobHandler jobHandler = jobHandlers.get(jobEntity.getJobHandlerType());\n                if (jobHandler != null) {\n                    jobHandler.execute(jobEntity, jobEntity.getJobHandlerConfiguration(), variableScope, getCommandContext());\n                } else {\n                    throw new FlowableException(\"No job handler registered for type \" + jobEntity.getJobHandlerType() + \n                                    \" in job config for engine: \" + jobServiceConfiguration.getEngineName() + \" for \" + jobEntity);\n                }\n                \n            } else {\n                throw new FlowableException(\"No job handler registered for type \" + jobEntity.getJobHandlerType() +\n                                \" in job config for engine: \" + jobServiceConfiguration.getEngineName() + \" for \" + jobEntity);\n            }\n            \n        } else {\n            throw new FlowableException(jobEntity + \" has no job handler type in job config for engine: \" + jobServiceConfiguration.getEngineName());\n        }\n    }\n\n    protected void executeHistoryJobHandler(HistoryJobEntity historyJobEntity) {\n        Map<String, HistoryJobHandler> jobHandlers = jobServiceConfiguration.getHistoryJobHandlers();\n        if (historyJobEntity.getJobHandlerType() != null) {\n            if (jobHandlers != null) {\n                HistoryJobHandler jobHandler = jobHandlers.get(historyJobEntity.getJobHandlerType());\n                if (jobHandler != null) {\n                    jobHandler.execute(historyJobEntity, historyJobEntity.getJobHandlerConfiguration(), getCommandContext(), jobServiceConfiguration);\n                } else {\n                    throw new FlowableException(\"No history job handler registered for type \" + historyJobEntity.getJobHandlerType() +\n                                    \" in job config for engine: \" + jobServiceConfiguration.getEngineName() + \" for \" + historyJobEntity);\n                }\n                \n            } else {\n                throw new FlowableException(\"No history job handler registered for type \" + historyJobEntity.getJobHandlerType() + \n                                \" in job config for engine: \" + jobServiceConfiguration.getEngineName() + \" for \" + historyJobEntity);","sourceCodeStart":548,"sourceCodeEnd":584,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/asyncexecutor/DefaultJobManager.java#L548-L584","documentation":"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.","triggerScenarios":"A JobEntity row (e.g. in ACT_RU_JOB) with NULL JOB_HANDLER_TYPE is passed to executeMessageJob/executeTimerJob -> executeJobHandler.","commonSituations":"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.","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."],"exampleFix":"// before\nMessageJobEntity job = jobService.createMessageJob();\njob.setJobHandlerConfiguration(\"cfg\");\n// jobHandlerType never set\n\n// after\nMessageJobEntity job = jobService.createMessageJob();\njob.setJobHandlerType(AsyncContinuationJobHandler.TYPE); // e.g. \"async-continuation\"\njob.setJobHandlerConfiguration(\"cfg\");","handlingStrategy":"validation","validationCode":"if (job.getJobHandlerType() == null || job.getJobHandlerType().isEmpty()) {\n    throw new IllegalStateException(\"Job \" + job.getId() + \" has no jobHandlerType\");\n}","typeGuard":"boolean hasHandlerType(JobEntity job) { return job.getJobHandlerType() != null && !job.getJobHandlerType().isEmpty(); }","tryCatchPattern":"try { jobManager.executeMessageJob(job); } catch (FlowableException e) { if (e.getMessage().endsWith(\"has no job handler type\")) { repairOrDeleteJobRow(job.getId()); } else throw e; }","preventionTips":["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."],"tags":["flowable","job-handler","null-field","data-integrity"],"backgroundTag":"missing-required-argument","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}