flowable/flowable-engine · error · FlowableObjectNotFoundException
No process definition found for key '${processDefinitionKey}
Error message
No process definition found for key '${processDefinitionKey}'. Fallback to default tenant was also applied. What it means
Thrown by resolveProcessDefinition when a tenantId was supplied, the lookup by key+tenant failed, and a fallback to the default tenant was attempted but also failed to find a definition for that key. Distinguishes the total lookup failure from the simple not-found case.
Source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/util/ProcessInstanceHelper.java:426
}
}
} else {
if (parentDeploymentId != null) {
processDefinition = processDefinitionEntityManager
.findProcessDefinitionByParentDeploymentAndKey(parentDeploymentId, processDefinitionKey);
}
if (processDefinition == null) {
processDefinition = processDefinitionEntityManager
.findLatestProcessDefinitionByKey(processDefinitionKey);
}
}
if (processDefinition == null) {
if (tenantId == null || ProcessEngineConfiguration.NO_TENANT_ID.equals(tenantId)) {
throw new FlowableObjectNotFoundException(
"No process definition found for key '" + processDefinitionKey + "'", ProcessDefinition.class);
} else if (fallbackToDefaultTenant) {
throw new FlowableObjectNotFoundException(
"No process definition found for key '" + processDefinitionKey + "'. Fallback to default tenant was also applied.", ProcessDefinition.class);
} else {
throw new FlowableObjectNotFoundException(
"Process definition with key '" + processDefinitionKey + "' and tenantId '" + tenantId + "' was not found", ProcessDefinition.class);
}
}
return processDefinition;
}
public void callCaseInstanceStateChangeCallbacks(CommandContext commandContext, ProcessInstance processInstance, String oldState, String newState) {
if (processInstance.getCallbackId() != null && processInstance.getCallbackType() != null) {
Map<String, List<RuntimeInstanceStateChangeCallback>> caseInstanceCallbacks = CommandContextUtil
.getProcessEngineConfiguration(commandContext).getProcessInstanceStateChangedCallbacks();
if (caseInstanceCallbacks != null && caseInstanceCallbacks.containsKey(processInstance.getCallbackType())) {
for (RuntimeInstanceStateChangeCallback caseInstanceCallback : caseInstanceCallbacks.get(processInstance.getCallbackType())) {
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Deploy the process to the requested tenantId: createDeployment().tenantId(tenant).deploy().
- Verify the key spelling against ProcessDefinitionQuery.processDefinitionTenantId(tenant).processDefinitionKey(key).
- Check which tenants hold the key: repositoryService.createProcessDefinitionQuery().processDefinitionKey(key).list() and use the matching tenant.
- If a fallback to the default tenant is intended, deploy a default-tenant (no tenantId) copy of the model.
Example fix
// before
runtimeService.startProcessInstanceByKey("order", "tenantB", vars); // deployed only to tenantA
// after
repositoryService.createDeployment().addClasspathResource("order.bpmn20.xml").tenantId("tenantB").deploy();
runtimeService.startProcessInstanceByKey("order", "tenantB", vars); Defensive patterns
Strategy: validation
Validate before calling
List<ProcessDefinition> defs = repositoryService.createProcessDefinitionQuery().processDefinitionKey(key).list();
boolean ok = defs.stream().anyMatch(d -> tenantId.equals(d.getTenantId())
|| ProcessEngineConfiguration.NO_TENANT_ID.equals(d.getTenantId()));
if (!ok) throw new IllegalStateException("Key '" + key + "' not deployed for tenant '" + tenantId + "' nor default"); Try / catch
try {
return runtimeService.startProcessInstanceByKey(key, tenantId, vars);
} catch (FlowableObjectNotFoundException e) {
if (e.getMessage().contains("Fallback to default tenant")) {
throw new IllegalStateException("Deploy for tenant '" + tenantId + "' and default tenant first", e);
}
throw e;
} Prevention
- Audit tenant deployments with a query on processDefinitionKey across tenants
- Standardize tenant ids in configuration, never ad-hoc strings
- Remember fallback only reaches the default (empty) tenant
- Deploy per-tenant copies in setup scripts
When it happens
Trigger: Starting a process with a tenantId (fallbackToDefaultTenant=true, the default behavior of startProcessInstanceByKey) where neither tenant 'myTenant' nor the default (empty) tenant has any version of the key.
Common situations: Multi-tenant deployments where the process was deployed to a different tenant than the one requested; default-tenant deployments removed during cleanup; expecting fallback to find tenant-specific definitions that don't share the key.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- No process definition found for key '${processDefinitionKey}
- Process definition with key '${processDefinitionKey}' and te
- No channel definition found for key '' for tenant identifier
- 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/1c7d690f8cdde3db.
Report an issue: GitHub.