flowable/flowable-engine · error · FlowableObjectNotFoundException
Process definition ${processDefinitionKey} was not found in
Error message
Process definition ${processDefinitionKey} was not found in sameDeployment[${isSameDeployment}] tenantId[${tenantId}] fallbackToDefaultTenant[${this.fallbackToDefaultTenant}] What it means
CallActivityBehavior.getProcessDefinitionByKey resolves the called process by key, honoring sameDeployment, tenantId and fallbackToDefaultTenant. If no matching deployed process definition is found under those constraints, it throws FlowableObjectNotFoundException detailing all the resolution parameters. This is the standard 'called process not deployed (or not visible to this tenant)' error.
Source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/behavior/CallActivityBehavior.java:329
if (tenantId == null || ProcessEngineConfiguration.NO_TENANT_ID.equals(tenantId)) {
processDefinition = processDefinitionEntityManager.findLatestProcessDefinitionByKey(processDefinitionKey);
} else {
processDefinition = processDefinitionEntityManager.findLatestProcessDefinitionByKeyAndTenantId(processDefinitionKey, tenantId);
if (processDefinition == null && ((this.fallbackToDefaultTenant != null && this.fallbackToDefaultTenant) || processEngineConfiguration.isFallbackToDefaultTenant())) {
String defaultTenant = processEngineConfiguration.getDefaultTenantProvider().getDefaultTenant(tenantId, ScopeTypes.BPMN, processDefinitionKey);
if (StringUtils.isNotEmpty(defaultTenant)) {
processDefinition = processDefinitionEntityManager.findLatestProcessDefinitionByKeyAndTenantId(
processDefinitionKey, defaultTenant);
} else {
processDefinition = processDefinitionEntityManager.findLatestProcessDefinitionByKey(processDefinitionKey);
}
}
}
if (processDefinition == null) {
throw new FlowableObjectNotFoundException("Process definition " + processDefinitionKey + " was not found in sameDeployment["+ isSameDeployment +
"] tenantId["+ tenantId+ "] fallbackToDefaultTenant["+ this.fallbackToDefaultTenant + "]");
}
return processDefinition;
}
protected String getCalledElementValue(DelegateExecution execution, ProcessEngineConfigurationImpl processEngineConfiguration) {
String calledElementValue = callActivity.getCalledElement();
if (Context.getProcessEngineConfiguration().isEnableProcessDefinitionInfoCache()){
ObjectNode taskElementProperties = BpmnOverrideContext
.getBpmnOverrideElementProperties(callActivity.getId(), execution.getProcessDefinitionId());
calledElementValue = getActiveValue(callActivity.getCalledElement(), DynamicBpmnConstants.CALL_ACTIVITY_CALLED_ELEMENT, taskElementProperties);
}
if (StringUtils.isNotEmpty(calledElementValue) && calledElementValue.matches(EXPRESSION_REGEX)) {
calledElementValue = (String) processEngineConfiguration.getExpressionManager().createExpression(calledElementValue).getValue(execution);
}
return calledElementValue;
}
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Deploy the process with the missing key (include its BPMN XML in the parent's BAR or deploy it separately for the same tenant).
- Set fallbackToDefaultTenant=true on the call activity if a tenantless default deployment of the subprocess should be used.
- Check what exists: repositoryService.createProcessDefinitionQuery().processDefinitionKey(key).processDefinitionTenantId(tenantId).list() and align tenantId/sameDeployment.
- If versioning independently, set sameDeployment=false so the latest definition by key across deployments is used.
- Fix typos in the calledElement key.
Example fix
// before: tenant 'acme' cannot see subprocess deployed without tenant, fallback disabled <callActivity id="c" calledElement="subProcess" flowable:fallbackToDefaultTenant="false"/> // after <callActivity id="c" calledElement="subProcess" flowable:fallbackToDefaultTenant="true"/>
Defensive patterns
Strategy: validation
Validate before calling
ProcessDefinition def = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("subProcess")
.processDefinitionTenantId(tenantId)
.latestVersion().singleResult();
if (def == null) throw new IllegalStateException("Deploy subprocess for tenant " + tenantId + " before starting parent"); Try / catch
try { startParent(); }
catch (FlowableObjectNotFoundException e) { if (e.getMessage().contains("Process definition")) { deployMissingSubProcess(); } else { throw e; } } Prevention
- Package subprocess BPMN in the same BAR as the caller when using sameDeployment.
- Enable fallbackToDefaultTenant for shared subprocess deployments.
- Query definitions per tenant in deployment smoke tests.
- Grep call activities and assert each calledElement key is deployed.
When it happens
Trigger: A call activity with calledElementType=key executes and: the key is not deployed at all; sameDeployment=true and the key isn't in the same deployment; the process is deployed under a different tenantId and fallbackToDefaultTenant=false.
Common situations: Sub process forgotten from the deployment BAR file; tenant-aware deployments where the tenant's deployment lacks the subprocess; sameDeployment=true combined with separately versioned subprocess deployments; key typos or renamed process keys.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- Cannot find process definition for key '{processDefinitionKe
- No process definition found for key '${processDefinitionKey}
- No process definition found for name:
- No decision found for key <decisionKey>. There was also no f
- No decision found for key <decisionKey>. There was also no f
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/0a767daf97d8a32c.
Report an issue: GitHub.