flowable/flowable-engine · error · FlowableIllegalArgumentException
Invalid action: '
Error message
Invalid action: '
What it means
executeTaskAction dispatches only on the known actions: claim, complete, delegate, resolve. Any other value in TaskActionRequest.action falls through to a FlowableIllegalArgumentException whose message embeds the offending action string (the bracketed message is the prefix before interpolation).
Solutions
- Use one of the supported action strings: claim, complete, delegate, resolve (all lowercase)
- Normalize/validate the action client-side before sending
- Check the ActionRequest constants (TaskActionRequest.ACTION_*) for the exact values supported by your Flowable version
Example fix
// before
{"action":"completeTask"}
// after
{"action":"complete"} Defensive patterns
Strategy: validation
Validate before calling
const SUPPORTED_ACTIONS = ['claim','complete','delegate','resolve'];
function assertValidAction(action) {
if (!SUPPORTED_ACTIONS.includes(action)) {
throw new Error(`Unsupported action '${action}'; use one of ${SUPPORTED_ACTIONS.join(', ')}`);
}
} Type guard
function isTaskAction(s) {
return ['claim','complete','delegate','resolve'].includes(s);
} Try / catch
try {
await post(`/cmmn-runtime/tasks/${taskId}`, { action });
} catch (e) {
if (e.status === 400 && /Invalid action/.test(e.body.message)) {
throw new Error(`'${action}' is not a supported CMMN task action`);
}
throw e;
} Prevention
- Normalize action strings to lowercase before sending
- Reference TaskActionRequest.ACTION_* constants instead of literals in Java clients
- Check the Flowable version's supported actions when upgrading (new actions are not backported)
When it happens
Trigger: POST /cmmn-runtime/tasks/{taskId} with {"action":"finish"}, {"action":"CLAIM"} (case-sensitive mismatch), a typo, or an action name valid only in the BPMN REST API.
Common situations: Case-sensitivity mistakes ('Claim' vs 'claim'); reusing action names from a different API; free-form UI input passed through without validation; new actions assumed to exist in this Flowable version.
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
- A request body was expected when executing a task action.
- Illegal action: ' '.
- Invalid action: ' '.
- Unsupported variable query operation
- Unsupported variable query operation: " +…
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/15187ae8a34e6728.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/task/TaskResource.java:138
}
if (TaskActionRequest.ACTION_COMPLETE.equals(actionRequest.getAction())) {
completeTask(task, actionRequest);
} else if (TaskActionRequest.ACTION_CLAIM.equals(actionRequest.getAction())) {
claimTask(task, actionRequest);
} else if (TaskActionRequest.ACTION_UNCLAIM.equals(actionRequest.getAction())) {
unclaimTask(task);
} else if (TaskActionRequest.ACTION_DELEGATE.equals(actionRequest.getAction())) {
delegateTask(task, actionRequest);
} else if (TaskActionRequest.ACTION_RESOLVE.equals(actionRequest.getAction())) {
resolveTask(task, actionRequest);
} else {
throw new FlowableIllegalArgumentException("Invalid action: '" + actionRequest.getAction() + "'.");
}
}
@ApiOperation(value = "Delete a task", tags = { "Tasks" }, code = 204)
@ApiImplicitParams({
@ApiImplicitParam(name = "cascadeHistory", dataType = "string", value = "Whether or not to delete the HistoricTask instance when deleting the task (if applicable). If not provided, this value defaults to false.", paramType = "query"),
@ApiImplicitParam(name = "deleteReason", dataType = "string", value = "Reason why the task is deleted. This value is ignored when cascadeHistory is true.", paramType = "query")
})
@ApiResponses(value = {
@ApiResponse(code = 204, message = "Indicates the task was found and has been deleted. Response-body is intentionally empty."),
@ApiResponse(code = 403, message = "Indicates the requested task cannot be deleted because it’s part of a workflow."),
@ApiResponse(code = 404, message = "Indicates the requested task was not found.")
})
@DeleteMapping(value = "/cmmn-runtime/tasks/{taskId}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteTask(@ApiParam(name = "taskId") @PathVariable String taskId, @ApiParam(hidden = true) @RequestParam(value = "cascadeHistory", required = false) Boolean cascadeHistory,
@ApiParam(hidden = true) @RequestParam(value = "deleteReason", required = false) String deleteReason) {
View on GitHub (pinned to d6d39ce1c6)