flowable/flowable-engine · error · FlowableIllegalArgumentException

Empty taskId is not allowed for HistoricTaskLogEntry

Error message

Empty taskId is not allowed for HistoricTaskLogEntry

What it means

Flowable throws this FlowableIllegalArgumentException when a HistoricTaskLogEntryBuilderImpl command is executed with an empty or null taskId. A task-log entry must reference a specific task, so the builder refuses to persist an entry without one. The check runs in execute() inside the command, i.e. when the log entry is actually written.

Solutions

  1. Set the taskId on the builder via .taskId(taskId) before executing the command.
  2. Verify the task id is non-empty with StringUtils.isNotEmpty before building the log entry.
  3. If the log is not task-scoped, use the correct builder/API for non-task log entries.
  4. Ensure the task actually exists and its id was propagated to the logging code.

Example fix

// before
TaskLogEntryBuilder b = ...; b.type("start").execute(); // empty taskId -> throws
// after
if (StringUtils.isNotEmpty(taskId)) {
    taskService.createTaskLogEntryBuilder().taskId(taskId).type("start").save();
}
Defensive patterns

Strategy: validation

Validate before calling

if (taskId == null || taskId.isEmpty()) {
    throw new IllegalArgumentException("taskId required for task log entry");
}
taskService.createTaskLogEntryBuilder().taskId(taskId)...;

Type guard

boolean hasTaskId(String id) { return id != null && !id.isEmpty(); }

Try / catch

try {
    builder.execute();
} catch (FlowableIllegalArgumentException e) {
    if (e.getMessage().contains("Empty taskId is not allowed")) {
        log.error("Attempted to write task log entry without taskId");
    } else { throw e; }
}

Prevention

When it happens

Trigger: Calling taskService... on a HistoricTaskLogEntryBuilder (e.g. addLogType(...) followed by execute/trigger) without setting taskId, or setting taskId to null/empty string.

Common situations: Logging helper code that records task events where the task id was not yet assigned (e.g. before task creation); passing a variable holding the task id that is null because the task lookup failed.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-task-service/src/main/java/org/flowable/task/service/impl/HistoricTaskLogEntryBuilderImpl.java:51

        super(task);
        this.commandExecutor = commandExecutor;
        this.taskServiceConfiguration = taskServiceConfiguration;
    }

    public HistoricTaskLogEntryBuilderImpl(CommandExecutor commandExecutor, TaskServiceConfiguration taskServiceConfiguration) {
        this.commandExecutor = commandExecutor;
        this.taskServiceConfiguration = taskServiceConfiguration;
    }

    @Override
    public void create() {
        this.commandExecutor.execute(this);
    }

    @Override
    public Void execute(CommandContext commandContext) {
        if (StringUtils.isEmpty(getTaskId())) {
            throw new FlowableIllegalArgumentException("Empty taskId is not allowed for HistoricTaskLogEntry");
        }
        if (StringUtils.isEmpty(getUserId())) {
            userId(Authentication.getAuthenticatedUserId());
        }
        if (timeStamp == null) {
            timeStamp(taskServiceConfiguration.getClock().getCurrentTime());
        }

        taskServiceConfiguration.getInternalHistoryTaskManager().recordHistoryUserTaskLog(this);
        return null;
    }

}

View on GitHub (pinned to d6d39ce1c6)