flowable/flowable-engine · error · FlowableForbiddenException
Cannot delete a task that is part of a process instance.
Error message
Cannot delete a task that is part of a process instance.
What it means
A FlowableForbiddenException thrown by deleteTask when the target runtime task has an executionId, meaning it was created by a running BPMN process instance. Standalone tasks can be deleted via the REST API, but process-linked tasks must be ended through the engine (e.g. complete) or by deleting the process instance.
Source
Thrown at modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/task/TaskResource.java:159
@ApiOperation(value = "Delete a task", tags = {"Tasks"}, code = 204)
@ApiImplicitParams({
@ApiImplicitParam(name = "cascadeHistory", dataType = "string", value = "Whether or not to delete the HistoricTask instance when deleting the task (if applicable). If not provided, this value defaults to false.", paramType = "query"),
@ApiImplicitParam(name = "deleteReason", dataType = "string", value = "Reason why the task is deleted. This value is ignored when cascadeHistory is true.", paramType = "query")
})
@ApiResponses(value = {
@ApiResponse(code = 204, message = "Indicates the task was found and has been deleted. Response-body is intentionally empty."),
@ApiResponse(code = 403, message = "Indicates the requested task cannot be deleted because it’s part of a workflow."),
@ApiResponse(code = 404, message = "Indicates the requested task was not found.")
})
@DeleteMapping(value = "/runtime/tasks/{taskId}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteTask(@ApiParam(name = "taskId") @PathVariable String taskId, @ApiParam(hidden = true) @RequestParam(value = "cascadeHistory", required = false) Boolean cascadeHistory,
@ApiParam(hidden = true) @RequestParam(value = "deleteReason", required = false) String deleteReason) {
Task taskToDelete = getTaskFromRequestWithoutAccessCheck(taskId);
if (taskToDelete.getExecutionId() != null) {
// Can not delete a task that is part of a process instance
throw new FlowableForbiddenException("Cannot delete a task that is part of a process instance.");
} else if (taskToDelete.getScopeId() != null && ScopeTypes.CMMN.equals(taskToDelete.getScopeType())) {
throw new FlowableForbiddenException("Cannot delete a task that is part of a case instance.");
}
if (restApiInterceptor != null) {
restApiInterceptor.deleteTask(taskToDelete);
}
if (cascadeHistory != null) {
// Ignore delete-reason since the task-history (where the reason is
// recorded) will be deleted anyway
taskService.deleteTask(taskToDelete.getId(), cascadeHistory);
} else {
// Delete with delete-reason
taskService.deleteTask(taskToDelete.getId(), deleteReason);
}
}
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Complete the task instead (POST /runtime/tasks/{taskId} with {"action":"complete"})
- If the whole flow should go away, delete the process instance: DELETE /runtime/process-instances/{processInstanceId}
- Filter task queries to standalone tasks (executionId null) before deleting
Example fix
// before if (task.getExecutionId() == null) restTemplate.delete(TASK_URL + "/" + task.getId()); restTemplate.delete(TASK_URL + "/" + task.getId()); // throws for process tasks // after if (task.getExecutionId() == null) restTemplate.delete(TASK_URL + "/" + task.getId()); else completeTask(task.getId());
Defensive patterns
Strategy: validation
Validate before calling
const task = await get('/runtime/tasks/'+taskId); if (task.executionId != null) { /* complete instead of delete */ } Type guard
function isStandaloneTask(t) { return t.executionId == null; } Try / catch
catch (e) { if (e.status === 403 && /part of a process instance/.test(e.body && e.body.message)) { /* complete the task or delete the process instance */ } else throw e; } Prevention
- Check executionId before any runtime task delete
- Prefer completing process tasks over deleting them
- Restrict bulk cleanup jobs to standalone tasks
When it happens
Trigger: DELETE /runtime/tasks/{taskId} for a task that appears in a process instance; the URL query params cascadeHistory/deleteReason are irrelevant here.
Common situations: Automated cleanup scripts iterating all runtime tasks and deleting them, hitting process-created tasks; confusion between standalone and process-scoped task lifecycle.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Cannot delete a task that is part of a case instance.
- Cannot delete a task that is part of a case instance.
- Cannot delete a task that is part of a process instance.
- ${workerId} does not hold a lock on the requested job
- Error converting resource stream
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/823f24736012f9c4.
Report an issue: GitHub.