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

  1. Use only: activate, suspend, claim, unclaim (exact lowercase strings).
  2. Remove the action field entirely if you only want to update businessKey/query variables — updates go through the non-action branch.
  3. 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

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


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)