{"record":{"id":"5a14f7121e1bf135","repo":"flowable/flowable-engine","slug":"taskid-is-null-5a14f7","errorCode":null,"errorMessage":"taskId is null","messagePattern":"taskId is null","errorType":"exception","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/DeleteHistoricTaskInstanceCmd.java","lineNumber":44,"sourceCode":"\n/**\n * @author Tijs Rademakers\n */\npublic class DeleteHistoricTaskInstanceCmd implements Command<Object>, Serializable {\n\n    private static final long serialVersionUID = 1L;\n    \n    protected String taskId;\n\n    public DeleteHistoricTaskInstanceCmd(String taskId) {\n        this.taskId = taskId;\n    }\n\n    @Override\n    public Object execute(CommandContext commandContext) {\n\n        if (taskId == null) {\n            throw new FlowableIllegalArgumentException(\"taskId is null\");\n        }\n\n        // Check if task is completed\n        HistoricTaskInstanceEntity historicTaskInstance = CommandContextUtil.getHistoricTaskService().getHistoricTask(taskId);\n\n        if (historicTaskInstance == null) {\n            throw new FlowableObjectNotFoundException(\"No historic task instance found with id: \" + taskId, HistoricTaskInstance.class);\n        }\n        if (historicTaskInstance.getEndTime() == null) {\n            throw new FlowableException(\"task does not have an endTime, cannot delete \" + historicTaskInstance);\n        }\n\n        CommandContextUtil.getCmmnHistoryManager(commandContext).recordHistoricTaskDeleted(historicTaskInstance);\n        \n        return null;\n    }\n\n}","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/DeleteHistoricTaskInstanceCmd.java#L26-L62","documentation":"DeleteHistoricTaskInstanceCmd validates taskId before fetching the historic task via the HistoricTaskService. A null taskId throws FlowableIllegalArgumentException(\"taskId is null\"). It can surface indirectly from activity behaviors (e.g. executeActivityBehavior) that delete historic tasks with an unpopulated id.","triggerScenarios":"Calling CmmnHistoryService.deleteHistoricTaskInstance(null) or delegating commands with a task entity whose id is null (unsaved task, mapping failure).","commonSituations":"Processing a task result from an empty query without null check; DTO mapping dropping the id field; cleanup listeners firing for tasks never persisted.","solutions":["Null/empty-check taskId before calling deleteHistoricTaskInstance","Ensure the source entity (Task/HistoricTaskInstance) actually has a persisted id before deleting","Log and skip null-id tasks in batch/listener code rather than throwing"],"exampleFix":"// before\nhistoryService.deleteHistoricTaskInstance(task.getId());\n// after\nif (task != null && task.getId() != null) {\n    historyService.deleteHistoricTaskInstance(task.getId());\n}","handlingStrategy":"validation","validationCode":"if (taskId == null || taskId.isEmpty()) { return; }\nhistoryService.deleteHistoricTaskInstance(taskId);","typeGuard":"boolean hasId(Task t) { return t != null && t.getId() != null && !t.getId().isEmpty(); }","tryCatchPattern":"try { historyService.deleteHistoricTaskInstance(taskId); }\ncatch (FlowableIllegalArgumentException e) { if (\"taskId is null\".equals(e.getMessage())) { log.warn(\"skipped historic task delete: null id\"); } else throw e; }","preventionTips":["Guard entity ids before deleting historic tasks","In listeners, skip tasks that were never persisted","Validate DTO mapping keeps the id field populated"],"tags":["cmmn","history","null-argument","task"],"backgroundTag":"null-argument","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}