flowable/flowable-engine · error · FlowableIllegalArgumentException

Invalid action: ' '.

Error message

Invalid action: '${action}'.

What it means

performPlanItemInstanceAction dispatches on the action string of a RestActionRequest (e.g. complete, enable, disable, start). Any action string outside the recognized set falls into the else branch and throws FlowableIllegalArgumentException, since no corresponding engine operation exists.

Solutions

  1. Use exactly one of the supported action strings handled by the method: complete, enable, disable, start (as matched via RestActionRequest constants).
  2. Compare against RestActionRequest constants or the REST documentation rather than free-form strings.
  3. Validate the action string client-side before POSTing.
  4. Catch FlowableIllegalArgumentException (HTTP 400) and show the allowed actions to the user.

Example fix

// before
{"action":"Complete"}
// after
{"action":"complete"}
Defensive patterns

Strategy: validation

Validate before calling

const ALLOWED = ['complete','enable','disable','start'];
if (!ALLOWED.includes(action)) throw new Error(`Invalid action: ${action}`);

Type guard

const isValidAction = (a) => ['complete','enable','disable','start'].includes(a);

Try / catch

try { await performAction(id, action); } catch (e) { if (e.status === 400 && /Invalid action/.test(e.message)) { /* show allowed actions */ } else { throw e; } }

Prevention

When it happens

Trigger: POST .../cmmn-runtime/plan-item-instances/{id}/action with body {"action":"..."} where the action is misspelled, in the wrong case, or not supported for this resource (e.g. 'complete' where not handled, 'trigger', 'resolve').

Common situations: Typos or casing mismatches in the action string; reusing action names valid on other Flowable REST resources (tasks/jobs); older client SDK sending actions removed in this 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


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/c3a0cc4deaa6d43d. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/planitem/PlanItemInstanceResource.java:82

        
        if (restApiInterceptor != null) {
            restApiInterceptor.doPlanItemInstanceAction(planItemInstance, actionRequest);
        }

        if (RestActionRequest.TRIGGER.equals(actionRequest.getAction())) {
            runtimeService.triggerPlanItemInstance(planItemInstance.getId());
            
        } else if (RestActionRequest.ENABLE.equals(actionRequest.getAction())) {
            runtimeService.startPlanItemInstance(planItemInstanceId);
            
        } else if (RestActionRequest.DISABLE.equals(actionRequest.getAction())) {
            runtimeService.disablePlanItemInstance(planItemInstanceId);
            
        } else if (RestActionRequest.START.equals(actionRequest.getAction())) {
            runtimeService.startPlanItemInstance(planItemInstanceId);
            
        } else {
            throw new FlowableIllegalArgumentException("Invalid action: '" + actionRequest.getAction() + "'.");
        }

        // Re-fetch the execution, could have changed due to action or even completed
        planItemInstance = runtimeService.createPlanItemInstanceQuery().planItemInstanceId(planItemInstance.getId()).singleResult();
        if (planItemInstance == null) {
            // Execution is finished, return empty body to inform user
            response.setStatus(HttpStatus.NO_CONTENT.value());
            return null;
        } else {
            return restResponseFactory.createPlanItemInstanceResponse(planItemInstance);
        }
    }
}

View on GitHub (pinned to d6d39ce1c6)