flowable/flowable-engine · error · FlowableIllegalArgumentException
Only one of caseDefinitionId or caseDefinitionKey should be…
Error message
Only one of caseDefinitionId or caseDefinitionKey should be set.
What it means
createCaseInstance allows only one way of resolving the case definition. If the request sets both caseDefinitionId and caseDefinitionKey (more than one parameter set), Flowable throws FlowableIllegalArgumentException (HTTP 400) because the target definition would be ambiguous.
Solutions
- Remove caseDefinitionId and keep only caseDefinitionKey (preferred when targeting the latest version)
- Or keep only caseDefinitionId when you must pin an exact deployed definition version
- Fix the client mapping so it sets exactly one of the two fields
- Validate the payload client-side before sending
Example fix
// before
{"caseDefinitionId":"myCase:1:4", "caseDefinitionKey":"myCase"}
// after
{"caseDefinitionKey":"myCase"} Defensive patterns
Strategy: validation
Validate before calling
int set = (request.getCaseDefinitionId() != null ? 1 : 0) + (request.getCaseDefinitionKey() != null ? 1 : 0);
if (set > 1) throw new IllegalArgumentException("Set only one of caseDefinitionId / caseDefinitionKey"); Type guard
null
Try / catch
try {
startCase(request);
} catch (HttpClientErrorException.BadRequest e) {
if (e.getResponseBodyAsString().contains("Only one of caseDefinitionId or caseDefinitionKey")) {
request.setCaseDefinitionId(null); // keep key only and retry
}
} Prevention
- Build start requests with exactly one definition reference
- Clear the other field when one is set programmatically
- Validate payloads with a schema before sending
When it happens
Trigger: POST /cmmn-runtime/case-instances with a body containing both caseDefinitionId and caseDefinitionKey (paramsSet > 1).
Common situations: Client code that always populates both fields from separate config values, template payloads copied between examples, generic start-form code that forwards all known definition fields.
Related errors
- Either caseDefinitionId or caseDefinitionKey is required.
- Only 'binary' and 'serializable' are supported as variable…
- TenantId can only be used with either caseDefinitionKey.
- Variable name is required.
- A group or a user is required to create an identity link.
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/1988db9c9bf728d6.
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:338
+ "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;
if (request.getStartFormVariables() != null) {
startFormVariables = new HashMap<>();
for (RestVariable variable : request.getStartFormVariables()) {
if (variable.getName() == null) {
throw new FlowableIllegalArgumentException("Variable name is required.");
}View on GitHub (pinned to d6d39ce1c6)