flowable/flowable-engine · error · FlowableIllegalArgumentException
caseDefinitionKey and caseDefinitionId are null
Error message
caseDefinitionKey and caseDefinitionId are null
What it means
CaseInstanceHelperImpl.getCaseDefinition resolves a CaseDefinition either by caseDefinitionId or by caseDefinitionKey (via the deployment cache/repository). If the CaseInstanceBuilder supplied neither identifier, the engine cannot locate which case definition to start and throws FlowableIllegalArgumentException. This is a fail-fast guard because starting a case without a definition reference is meaningless.
Solutions
- Set caseDefinitionKey (e.g. builder.caseDefinitionKey("myCase")) before calling startCaseInstance.
- Alternatively set the exact caseDefinitionId if you resolved the deployed definition already.
- Validate the incoming request/dto for a non-null definition key or id before invoking the engine.
Example fix
// before
cmmnRuntimeService.createCaseInstanceBuilder().businessKey("BK-1").start();
// after
cmmnRuntimeService.createCaseInstanceBuilder()
.caseDefinitionKey("loanApplicationCase")
.businessKey("BK-1")
.start(); Defensive patterns
Strategy: validation
Validate before calling
if (caseDefinitionKey == null && caseDefinitionId == null) {
throw new IllegalArgumentException("Provide caseDefinitionKey or caseDefinitionId before starting a case instance");
} Try / catch
try {
runtimeService.createCaseInstanceBuilder().caseDefinitionKey(key).start();
} catch (FlowableIllegalArgumentException e) {
if (e.getMessage().contains("caseDefinitionKey and caseDefinitionId are null")) {
// surface a 400 to the caller indicating the definition reference is required
}
throw e;
} Prevention
- Always set at least caseDefinitionKey in every CaseInstanceBuilder usage.
- Validate the start-request DTO at the controller/API layer before touching the engine.
- Write a unit test asserting a start without a definition reference fails fast in your own layer.
When it happens
Trigger: Calling CmmnRuntimeService.startCaseInstance (or the async variant) with a CaseInstanceBuilder where both caseDefinitionId and caseDefinitionKey are null/never set.
Common situations: Building the start request dynamically from user input or a request payload where the definition reference key was omitted; copying builder code that set the id but was refactored; REST/API layer dropping the field when deserializing the start request.
Related errors
- Case definition category is null
- Case definition id is null
- Case definition key is null
- Case instance id is null
- caseInstanceId is null
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/2623c7cefd24470e.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/CaseInstanceHelperImpl.java:183
CmmnDeploymentManager deploymentManager = cmmnEngineConfiguration.getDeploymentManager();
caseDefinition = deploymentManager.findDeployedCaseDefinitionById(caseDefinitionId);
} else if (caseInstanceBuilder.getCaseDefinitionKey() != null) {
String caseDefinitionKey = caseInstanceBuilder.getCaseDefinitionKey();
String tenantId = caseInstanceBuilder.getTenantId();
String parentDeploymentId = caseInstanceBuilder.getCaseDefinitionParentDeploymentId();
caseDefinition = resolveCaseDefinition(caseDefinitionKey, tenantId,
caseInstanceBuilder.isFallbackToDefaultTenant() || cmmnEngineConfiguration.isFallbackToDefaultTenant(),
parentDeploymentId);
if (caseDefinition != null && tenantId != null && !CmmnEngineConfiguration.NO_TENANT_ID.equals(tenantId)
&& !tenantId.equals(caseDefinition.getTenantId())) {
// Case definition comes from the fallback to the default tenant
caseInstanceBuilder.overrideCaseDefinitionTenantId(tenantId);
}
} else {
throw new FlowableIllegalArgumentException("caseDefinitionKey and caseDefinitionId are null");
}
return caseDefinition;
}
protected CaseInstanceEntity startCaseInstance(CommandContext commandContext, CaseDefinition caseDefinition, CaseInstanceBuilder caseInstanceBuilder) {
CmmnModel cmmnModel = getCmmnModel(commandContext, caseDefinition);
Case caseModel = getCaseModel(caseDefinition, cmmnModel);
CaseInstanceEntity caseInstanceEntity = initializeCaseInstanceEntity(commandContext, caseDefinition,
cmmnModel, caseModel, caseInstanceBuilder);
if (!caseModel.isAsync()) {
// The InitPlanModelOperation will take care of initializing all the child plan items of that stage
CommandContextUtil.getAgenda(commandContext).planInitPlanModelOperation(caseInstanceEntity);
CaseInstanceLifeCycleListenerUtil.callLifecycleListeners(commandContext, caseInstanceEntity, "", CaseInstanceState.ACTIVE);
FlowableEventDispatcher eventDispatcher = cmmnEngineConfiguration.getEventDispatcher();
if (eventDispatcher != null && eventDispatcher.isEnabled()) {View on GitHub (pinned to d6d39ce1c6)