flowable/flowable-engine · error · ActivitiException

Cannot add a comment to a suspended task

Error message

Cannot add a comment to a suspended task

What it means

AddCommentCmd.execute rejects adding a comment to a task whose isSuspended() is true, via getSuspendedTaskException(). While a task's process instance is suspended, state-changing operations like commenting are blocked by design.

Solutions

  1. Activate the process instance first: runtimeService.activateProcessInstanceById(task.getProcessInstanceId()).
  2. Check suspension before commenting: task.isSuspended() or the execution's suspension state, and defer/comment elsewhere.
  3. Use the process-level API only after confirming the definition/instance is active via ProcessDefinitionQuery/ProcessInstanceQuery suspension state.

Example fix

// before
taskService.addComment(taskId, null, "note");
// after
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if (task != null && !task.isSuspended()) {
    taskService.addComment(taskId, null, "note");
}
Defensive patterns

Strategy: validation

Validate before calling

Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if (task != null && task.isSuspended()) {
    throw new IllegalStateException("Task " + taskId + " is suspended");
}

Try / catch

try {
    taskService.addComment(taskId, null, message);
} catch (ActivitiException e) {
    if ("Cannot add a comment to a suspended task".equals(e.getMessage())) {
        logger.info("Deferring comment; task {} suspended", taskId);
    } else { throw e; }
}

Prevention

When it happens

Trigger: Calling TaskService.addComment(taskId, ...) (or createTaskComment) where the target task belongs to a suspended process instance — e.g. after suspendProcessInstanceById or a suspend defined on the process definition.

Common situations: Users of a UI try to add remarks while the workflow is administratively paused; batch jobs post comments to tasks during a suspension window; tests that suspend instances but keep writing comments.

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/c0de8a55f897ab9c. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/cmd/AddCommentCmd.java:64

        this.taskId = taskId;
        this.processInstanceId = processInstanceId;
        this.type = type;
        this.message = message;
    }

    @Override
    public Comment execute(CommandContext commandContext) {

        // Validate task
        if (taskId != null) {
            TaskEntity task = commandContext.getTaskEntityManager().findTaskById(taskId);

            if (task == null) {
                throw new ActivitiObjectNotFoundException("Cannot find task with id " + taskId, Task.class);
            }

            if (task.isSuspended()) {
                throw new ActivitiException(getSuspendedTaskException());
            }
        }

        if (processInstanceId != null) {
            ExecutionEntity execution = commandContext.getExecutionEntityManager().findExecutionById(processInstanceId);

            if (execution == null) {
                throw new ActivitiObjectNotFoundException("execution " + processInstanceId + " doesn't exist", Execution.class);
            }

            if (execution.isSuspended()) {
                throw new ActivitiException(getSuspendedExceptionMessage());
            }
        }

        String userId = Authentication.getAuthenticatedUserId();
        CommentEntity comment = new CommentEntity();
        comment.setUserId(userId);

View on GitHub (pinned to d6d39ce1c6)