flowable/flowable-engine · error · FlowableIllegalArgumentException
Invalid action: ' '.
Error message
Invalid action: '${action}'. What it means
Flowable REST throws FlowableIllegalArgumentException when PUT /runtime/process-instances/{id} carries an 'action' property whose value is not one of the supported actions (activate, suspend, claim, unclaim). Unknown action strings are rejected.
Solutions
- Use only: activate, suspend, claim, unclaim (exact lowercase strings).
- Remove the action field entirely if you only want to update businessKey/query variables — updates go through the non-action branch.
- Check the ProcessInstanceAction constants in the Flowable version you target.
Example fix
// before
{"action": "resume"}
// after
{"action": "activate"} Defensive patterns
Strategy: validation
Validate before calling
const allowed = ['activate','suspend','claim','unclaim']; if (body.action && !allowed.includes(body.action)) throw new Error('invalid action: ' + body.action); Type guard
const isValidAction = (a) => ['activate','suspend','claim','unclaim'].includes(a);
Prevention
- Keep action strings in a shared constant module
- Re-check allowed actions after Flowable version upgrades
- Send updates without an action field when not performing an action
When it happens
Trigger: PUT with body {"action":"cancel"} or {"action":"ACTIVATE"} (case-sensitive check against ACTION_* constants); typo like 'suspende'.
Common situations: Client written against Activiti 5 API with actions Flowable dropped or renamed; case-sensitivity assumption; migrated code sending custom actions.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- ${cause}
- Could not find a process instance with id '" +…
- Illegal action: ' '.
- Invalid action: '
- Unsupported variable query operation
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/73c1534b3fafc7a0.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ProcessInstanceResource.java:142
if (ProcessInstanceUpdateRequest.ACTION_ACTIVATE.equals(updateRequest.getAction())) {
return activateProcessInstance(processInstance);
} else if (ProcessInstanceUpdateRequest.ACTION_SUSPEND.equals(updateRequest.getAction())) {
return suspendProcessInstance(processInstance);
} else if (ProcessInstanceUpdateRequest.ACTION_CLAIM.equals(updateRequest.getAction())) {
runtimeService.claimProcessInstance(processInstanceId, updateRequest.getAssignee());
processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
return restResponseFactory.createProcessInstanceResponse(processInstance);
} else if (ProcessInstanceUpdateRequest.ACTION_UNCLAIM.equals(updateRequest.getAction())) {
runtimeService.unclaimProcessInstance(processInstanceId);
processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
return restResponseFactory.createProcessInstanceResponse(processInstance);
} else {
throw new FlowableIllegalArgumentException("Invalid action: '" + updateRequest.getAction() + "'.");
}
} else { // update
boolean hasUpdates = false;
ProcessInstanceUpdateBuilder updateBuilder = runtimeService.createProcessInstanceUpdateBuilder(processInstanceId);
if (updateRequest.getName() != null) {
updateBuilder.name(updateRequest.getName());
hasUpdates = true;
}
if (updateRequest.getBusinessKey() != null) {
updateBuilder.businessKey(updateRequest.getBusinessKey());
hasUpdates = true;
}
if (updateRequest.getBusinessStatus() != null) {
updateBuilder.businessStatus(updateRequest.getBusinessStatus());
hasUpdates = true;View on GitHub (pinned to d6d39ce1c6)