flowable/flowable-engine · error · FlowableException

UserTask should not be signalled before complete for +…

Error message

UserTask should not be signalled before complete for + taskEntity

What it means

UserTaskActivityBehavior.trigger is invoked when a signal/trigger arrives at the waiting user-task execution. If the execution still has a non-deleted task, the task was never completed, and signalling it is illegal; the engine throws this FlowableException. Only after the task is completed (deleted/moved on) should the execution be left.

Solutions

  1. Complete the task instead: call TaskService.complete(taskId) rather than runtimeService.trigger(executionId)
  2. Check taskEntity.isDeleted()/task state; only signal once the task no longer exists for that execution
  3. If using a timeout, attach a boundary timer event to the user task instead of signalling the execution manually
  4. Verify custom code that auto-completes tasks marks/deletes them before leaving the execution

Example fix

// before
runtimeService.trigger(executionId);
// after
Task task = taskService.createTaskQuery().executionId(executionId).singleResult();
taskService.complete(task.getId());
Defensive patterns

Strategy: try-catch

Validate before calling

Task t = taskService.createTaskQuery()
    .executionId(executionId).singleResult();
if (t != null) {
    throw new IllegalStateException("Complete task " + t.getId() + " instead of signalling execution " + executionId);
}

Try / catch

try {
    runtimeService.trigger(executionId);
} catch (FlowableException e) {
    if (e.getMessage().startsWith("UserTask should not be signalled")) {
        Task t = taskService.createTaskQuery().executionId(executionId).singleResult();
        if (t != null) taskService.complete(t.getId());
    }
}

Prevention

When it happens

Trigger: Calling RuntimeService.trigger(executionId) (or signal) on an execution currently sitting at a user task whose task is still active; boundary-event/boundary logic or custom code signalling the execution directly instead of completing the TaskService task.

Common situations: Custom timeout or escalation logic calling taskService-completion versus execution.trigger incorrectly; boundary events wiring mistakes; scripts that signal the process instead of calling TaskService.complete(taskId).

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/behavior/UserTaskActivityBehavior.java:340

                if (formKeyValue != null) {
                    formKey = formKeyValue.toString();
                }
            } catch (FlowableException e) {
                formKey = beforeContext.getFormKey();
                LOGGER.warn("property not found in task formKey expression {}", e.getMessage());
            }
            task.setFormKey(formKey);
        }
    }

    @Override
    public void trigger(DelegateExecution execution, String signalName, Object signalData) {
        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration();
        List<TaskEntity> taskEntities = processEngineConfiguration.getTaskServiceConfiguration().getTaskService()
                .findTasksByExecutionId(execution.getId()); // Should be only one
        for (TaskEntity taskEntity : taskEntities) {
            if (!taskEntity.isDeleted()) {
                throw new FlowableException("UserTask should not be signalled before complete for " + taskEntity);
            }
        }

        leave(execution);
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    protected void handleAssignments(TaskService taskService, String assignee, String owner, List<String> candidateUsers,
            List<String> candidateGroups, TaskEntity task, ExpressionManager expressionManager, DelegateExecution execution, 
            ProcessEngineConfigurationImpl processEngineConfiguration) {

        if (StringUtils.isNotEmpty(assignee)) {
            Object assigneeExpressionValue = expressionManager.createExpression(assignee).getValue(execution);
            String assigneeValue = null;
            if (assigneeExpressionValue != null) {
                assigneeValue = assigneeExpressionValue.toString();
            }

View on GitHub (pinned to d6d39ce1c6)