flowable/flowable-engine · error · FlowableIllegalArgumentException

Either caseDefinitionId or caseDefinitionKey is required.

Error message

Either caseDefinitionId or caseDefinitionKey is required.

What it means

createCaseInstance in the CMMN REST API requires the request body to identify which case definition to start. If neither caseDefinitionId nor caseDefinitionKey is set in CaseInstanceCreateRequest, it throws FlowableIllegalArgumentException (HTTP 400) because there is no way to resolve the definition.

Solutions

  1. Add caseDefinitionKey (e.g. "caseDefinitionKey":"myCase") to the request body — the usual choice
  2. Or add caseDefinitionId if you have the deployed definition's id
  3. Verify the client DTO actually serializes the field (correct getter/property name, non-null value)
  4. Check the request body's Content-Type is application/json so the fields bind correctly

Example fix

// before
{"variables": [{"name":"a","value":1}]}
// after
{"caseDefinitionKey":"myCase", "variables": [{"name":"a","value":1}]}
Defensive patterns

Strategy: validation

Validate before calling

if (request.getCaseDefinitionId() == null && request.getCaseDefinitionKey() == null) {
    throw new IllegalArgumentException("Set caseDefinitionId or caseDefinitionKey before starting a case instance");
}

Type guard

null

Try / catch

try {
    startCase(request);
} catch (HttpClientErrorException.BadRequest e) {
    if (e.getResponseBodyAsString().contains("Either caseDefinitionId or caseDefinitionKey is required")) {
        log.error("Case start request missing definition reference");
    }
}

Prevention

When it happens

Trigger: POST /cmmn-runtime/case-instances with a JSON body that omits both caseDefinitionId and caseDefinitionKey (e.g. body contains only variables, tenantId, or is effectively empty).

Common situations: Hand-written JSON payloads missing the definition fields, client DTO mapping bugs where the field is not serialized (wrong property name, null after mapping), copying request templates from other Flowable APIs that use different field names.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/CaseInstanceCollectionResource.java:332

    @ApiOperation(value = "Start a case instance", tags = { "Case Instances" },
            notes = "Note that also a *transientVariables* property is accepted as part of this json, that follows the same structure as the *variables* property.\n\n"
            + "Only one of *caseDefinitionId* or *caseDefinitionKey* an be used in the request body.\n\n"
            + "Parameters *businessKey*, *variables* and *tenantId* are optional.\n\n"
            + "If tenantId is omitted, the default tenant will be used.\n\n "
            + "It is possible to send variables, transientVariables and startFormVariables in one request.\n\n"
            + "More information about the variable format can be found in the REST variables section.\n\n "
            + "Note that the variable-scope that is supplied is ignored, case-variables are always local.\n\n",
            code = 201)
    @ApiResponses(value = {
            @ApiResponse(code = 201, message = "Indicates the case instance was created."),
            @ApiResponse(code = 400, message = "Indicates either the case definition was not found (based on id or key), no process is started by sending the given message or an invalid variable has been passed. Status description contains additional information about the error.")
    })
    @PostMapping(value = "/cmmn-runtime/case-instances", produces = "application/json")
    @ResponseStatus(HttpStatus.CREATED)
    public CaseInstanceResponse createCaseInstance(@RequestBody CaseInstanceCreateRequest request) {

        if (request.getCaseDefinitionId() == null && request.getCaseDefinitionKey() == null) {
            throw new FlowableIllegalArgumentException("Either caseDefinitionId or caseDefinitionKey is required.");
        }

        int paramsSet = ((request.getCaseDefinitionId() != null) ? 1 : 0) + ((request.getCaseDefinitionKey() != null) ? 1 : 0);

        if (paramsSet > 1) {
            throw new FlowableIllegalArgumentException("Only one of caseDefinitionId or caseDefinitionKey should be set.");
        }

        if (request.isTenantSet()) {
            // Tenant-id can only be used with either key or message
            if (request.getCaseDefinitionId() != null) {
                throw new FlowableIllegalArgumentException("TenantId can only be used with either caseDefinitionKey.");
            }
        }

        Map<String, Object> startVariables = null;
        Map<String, Object> transientVariables = null;
        Map<String, Object> startFormVariables = null;

View on GitHub (pinned to d6d39ce1c6)