{"record":{"id":"46ab26f8a261503a","repo":"flowable/flowable-engine","slug":"no-history-job-handler-registered-for-type","errorCode":null,"errorMessage":"No history job handler registered for type ","messagePattern":"No history job handler registered for type ","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":578,"sourceCode":"            } 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);\n            }\n            \n        } else {\n            throw new FlowableException(\"Async \" + historyJobEntity + \" has no job handler type in job config for engine: \" + jobServiceConfiguration.getEngineName());\n        }\n    }\n\n    protected boolean isValidTime(JobEntity timerEntity, Date newTimerDate, VariableScope variableScope) {\n        BusinessCalendar businessCalendar = jobServiceConfiguration.getBusinessCalendarManager().getBusinessCalendar(\n                getBusinessCalendarName(timerEntity, variableScope));\n        return businessCalendar.validateDuedate(timerEntity.getRepeat(), timerEntity.getMaxIterations(), timerEntity.getEndDate(), newTimerDate);\n    }","sourceCodeStart":560,"sourceCodeEnd":596,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/asyncexecutor/DefaultJobManager.java#L560-L596","documentation":"executeHistoryJobHandler resolves the history job's handler type in the engine's HistoryJobHandler map. If a handler for historyJobEntity.getJobHandlerType() is not found in a non-empty map, Flowable throws this FlowableException. History jobs (e.g. async history processing) need a registered handler to be executed.","triggerScenarios":"executeHistoryJob -> executeHistoryJobHandler with a history job whose handler type (typically 'async-history') is absent from jobServiceConfiguration.getHistoryJobHandlers().","commonSituations":"Enabling async history without the history job handlers being initialized; custom HistoryJobHandler not registered via processEngineConfiguration.setAsyncHistoryEnabled + custom handlers; engines configured with asyncHistoryEnabled but a stripped-down job service configuration.","solutions":["Verify async history is configured through the standard ProcessEngineConfigurationImpl (asyncHistoryEnabled=true) so default history handlers register at bootstrap.","Register custom history handlers via the configuration's history job handler map.","Check the JOB_HANDLER_TYPE of the failing history job row against registered handler keys.","Align Flowable versions if history jobs were written by a different engine version."],"exampleFix":"// before\n// async history on, but engine built manually, handlers missing\ncfg.setAsyncHistoryEnabled(true);\n\n// after\ncfg.setAsyncHistoryEnabled(true);\nList<HistoryJobHandler> historyHandlers = new ArrayList<>();\nhistoryHandlers.add(new AsyncHistoryJobHandler());\ncfg.setCustomHistoryJobHandlers(historyHandlers); // or rely on default init","handlingStrategy":"validation","validationCode":"Map<String, HistoryJobHandler> handlers = jobServiceConfiguration.getHistoryJobHandlers();\nif (handlers == null || !handlers.containsKey(historyJob.getJobHandlerType())) {\n    throw new IllegalStateException(\"Unregistered history job handler: \" + historyJob.getJobHandlerType());\n}","typeGuard":null,"tryCatchPattern":"try { historyJobManager.executeHistoryJob(job); } catch (FlowableException e) { if (e.getMessage().startsWith(\"No history job handler registered\")) { registerHistoryHandlerAndRetry(job); } else throw e; }","preventionTips":["Enable async history through standard ProcessEngineConfigurationImpl settings.","Register custom HistoryJobHandlers in engine configuration.","Check handler-type keys after Flowable version upgrades.","Monitor logs for handler-registration warnings at bootstrap."],"tags":["flowable","async-history","job-handler","missing-registration"],"backgroundTag":"missing-dependency","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"}