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
- Set the taskId on the builder via .taskId(taskId) before executing the command.
- Verify the task id is non-empty with StringUtils.isNotEmpty before building the log entry.
- If the log is not task-scoped, use the correct builder/API for non-task log entries.
- 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
- Only create task log entries after the task id is known/persisted
- Wrap log-entry creation in a helper that asserts a non-empty task id
- Verify task lookup succeeded before logging events for it
- Skip (or defer) logging when the task id is unavailable instead of failing
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
- appsDefinitionIds is null
- at least one of userId or groups must be provided
- Business status is null
- Candidate user is null
- Case definition keys is null
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)