flowable/flowable-engine · error · FlowableIllegalArgumentException
taskId or processInstanceId is required
Error message
taskId or processInstanceId is required
What it means
GetHistoricIdentityLinksForTaskCmd accepts either a taskId or a processInstanceId, but throws FlowableIllegalArgumentException when both are null. It retrieves historic identity links (users/groups involved) for a task or a whole process instance, so at least one selector is required.
Solutions
- Ensure at least one of taskId or processInstanceId is non-null before constructing the command.
- Add a pre-check that raises a clear caller-side error naming the missing selector.
- If neither id is available, use a different history query (e.g. query historic identity links by type/user) instead of this command.
Example fix
// before
historyService.findHistoricIdentityLinksForTask(taskId, processInstanceId);
// after
if (taskId == null && processInstanceId == null) {
throw new IllegalArgumentException("Provide taskId or processInstanceId to query historic identity links");
}
historyService.findHistoricIdentityLinksForTask(taskId, processInstanceId); Defensive patterns
Strategy: validation
Validate before calling
if (taskId == null && processInstanceId == null) {
throw new IllegalArgumentException("Either taskId or processInstanceId must be provided");
} Try / catch
try {
return historyService.findHistoricIdentityLinksForTask(taskId, processInstanceId);
} catch (FlowableIllegalArgumentException e) {
return Collections.emptyList();
} Prevention
- Assert one selector is present at the API boundary before calling engine commands
- Validate optional request parameters for history viewers before dispatching queries
- Centralize the check in a helper to avoid copy-paste drift
When it happens
Trigger: new GetHistoricIdentityLinksForTaskCmd(null, null), typically when optional taskId/processInstanceId parameters both resolve to null at the call site, or when routing logic fails to populate either argument.
Common situations: Building a generic history viewer where the caller passes whichever id it has and both are absent; copy-pasted calls to the identity-link API without filling in parameters; tasks/instances already removed from history so the caller's ids were nulled out.
Understand the failure class
Background: "mutually exclusive" flag errors: what "can't supply both nx and xx", "--raw is not compatible with -i" and "cannot be used with" mean, and how to fix them — this error's family across 29 libraries.
Related errors
- processInstanceId is required
- A group or a user is required to create an identity link.
- A process instance id is required, but the provided id '" +…
- A process instance id is required, but the provided id
- activityId is null
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/8a6a32f09d8d097a.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/cmd/GetHistoricIdentityLinksForTaskCmd.java:42
import org.flowable.identitylink.api.IdentityLinkType;
import org.flowable.identitylink.api.history.HistoricIdentityLink;
import org.flowable.identitylink.service.HistoricIdentityLinkService;
import org.flowable.identitylink.service.impl.persistence.entity.HistoricIdentityLinkEntity;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.service.impl.persistence.entity.HistoricTaskInstanceEntity;
/**
* @author Frederik Heremans
*/
public class GetHistoricIdentityLinksForTaskCmd implements Command<List<HistoricIdentityLink>>, Serializable {
private static final long serialVersionUID = 1L;
protected String taskId;
protected String processInstanceId;
public GetHistoricIdentityLinksForTaskCmd(String taskId, String processInstanceId) {
if (taskId == null && processInstanceId == null) {
throw new FlowableIllegalArgumentException("taskId or processInstanceId is required");
}
this.taskId = taskId;
this.processInstanceId = processInstanceId;
}
@Override
public List<HistoricIdentityLink> execute(CommandContext commandContext) {
if (taskId != null) {
return getLinksForTask(commandContext);
} else {
return getLinksForProcessInstance(commandContext);
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
protected List<HistoricIdentityLink> getLinksForTask(CommandContext commandContext) {
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
HistoricTaskInstanceEntity task = processEngineConfiguration.getTaskServiceConfiguration().getHistoricTaskService().getHistoricTask(taskId);View on GitHub (pinned to d6d39ce1c6)