flowable/flowable-engine · error · FlowableIllegalArgumentException
A process instance id is required, but the provided id '" +
Error message
A process instance id is required, but the provided id '" + processInstanceId + "' points to a child execution of process instance '" + processInstance.getProcessInstanceId() + "'. Please invoke the " + getClass().getSimpleName() + " with a root execution id."
What it means
ProcessInstanceClaimCmd requires the id of the ROOT execution (the process instance itself). If the id resolves to a child/concurrent execution (isProcessInstanceType() is false), it throws FlowableIllegalArgumentException telling the caller to pass a root execution id instead.
Source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/cmd/ProcessInstanceClaimCmd.java:60
public ProcessInstanceClaimCmd(String processInstanceId, String userId) {
if (processInstanceId == null || processInstanceId.isEmpty()) {
throw new FlowableIllegalArgumentException("The process instance id is mandatory, but '" + processInstanceId + "' has been provided.");
}
this.processInstanceId = processInstanceId;
this.userId = userId;
}
@Override
public Void execute(CommandContext commandContext) {
ExecutionEntityManager executionManager = CommandContextUtil.getExecutionEntityManager(commandContext);
ExecutionEntity processInstance = executionManager.findById(processInstanceId);
if (processInstance == null) {
throw new FlowableObjectNotFoundException("No process instance found for id = '" + processInstanceId + "'.", ProcessInstance.class);
} else if (!processInstance.isProcessInstanceType()) {
throw new FlowableIllegalArgumentException("A process instance id is required, but the provided id " + "'" + processInstanceId + "' " + "points to a child execution of process instance " + "'"
+ processInstance.getProcessInstanceId() + "'. " + "Please invoke the " + getClass().getSimpleName() + " with a root execution id.");
}
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
if (userId != null) {
List<IdentityLinkEntity> identityLinks = processEngineConfiguration.getIdentityLinkServiceConfiguration()
.getIdentityLinkService().findIdentityLinksByProcessInstanceId(processInstanceId);
for (IdentityLinkEntity identityLink : identityLinks) {
if (IdentityLinkType.ASSIGNEE.equals(identityLink.getType())) {
throw new FlowableException("Process instance '" + processInstanceId + "' is already claimed.");
}
}
IdentityLinkUtil.createProcessInstanceIdentityLink(processInstance, userId, null, IdentityLinkType.ASSIGNEE);
executionManager.updateProcessInstanceClaimTime(processInstance,
processEngineConfiguration.getClock().getCurrentTime(), userId);
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Pass the processInstanceId (execution.getId() where isProcessInstanceType() is true / execution.getProcessInstanceId()) instead of a child execution id.
- When iterating executions, filter with executionQuery.processInstanceId(pid) and take the root, or check ProcessInstance type before selecting the id.
- Catch FlowableIllegalArgumentException; if the message mentions a parent process instance id, extract it and retry the claim on the root id.
- Store and propagate processInstanceId (not executionId) wherever claim/unclaim operations will be needed.
Example fix
// before Execution exec = runtimeService.createExecutionQuery().executionId(childExecutionId).singleResult(); managementService.executeCommand(new ProcessInstanceClaimCmd(childExecutionId, userId)); // after Execution exec = runtimeService.createExecutionQuery().executionId(childExecutionId).singleResult(); String rootId = exec.getProcessInstanceId(); // root execution id managementService.executeCommand(new ProcessInstanceClaimCmd(rootId, userId));
Defensive patterns
Strategy: validation
Validate before calling
Execution exec = runtimeService.createExecutionQuery().executionId(id).singleResult();
if (exec == null || !exec.isProcessInstanceType()) { throw new IllegalArgumentException("A root process instance id is required"); } Type guard
boolean isRootProcessInstanceId(String id) {
Execution e = runtimeService.createExecutionQuery().executionId(id).singleResult();
return e != null && e.isProcessInstanceType();
} Try / catch
try {
managementService.executeCommand(new ProcessInstanceClaimCmd(id, userId));
} catch (FlowableIllegalArgumentException e) {
if (e.getMessage().contains("child execution")) {
// retry with the parent process instance id reported in the message
} else { throw e; }
} Prevention
- Always store processInstanceId (not executionId) for instance-level operations.
- When iterating ExecutionQuery results, filter to the root execution.
- Name API fields explicitly (processInstanceId vs executionId) to avoid mixups.
- Add integration tests with multi-execution (async/concurrent) processes.
When it happens
Trigger: Executing ProcessInstanceClaimCmd with an execution id obtained from ExecutionQuery results for a child scope (e.g. a concurrent or event-scope execution) rather than the process instance id.
Common situations: Iterating RuntimeService.createExecutionQuery() results and using each execution's id; confusing executionId with processInstanceId in process variable/callback payloads; nested/async-continuation processes producing extra child executions.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- A process instance id is required, but the provided id '${pr
- Could not start process instance with business key ${key}
- Job <jobId> parent is not process instance
- No processDefinitionId, processDefinitionKey nor messageName
- No processDefinitionId, processDefinitionKey provided
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/b3081f71dc90fc09.
Report an issue: GitHub.