flowable/flowable-engine · error · FlowableObjectNotFoundException
Process definition with key '${processDefinitionKey}' and te
Error message
Process definition with key '${processDefinitionKey}' and tenantId '${tenantId}' was not found What it means
Thrown by resolveProcessDefinition when a specific tenantId was supplied and no process definition exists with that key AND tenantId. Unlike the fallback case, no default-tenant fallback was requested or it was disabled, so the engine reports the exact key+tenant combination that was not found.
Source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/util/ProcessInstanceHelper.java:429
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())) {
caseInstanceCallback.stateChanged(new CallbackData(processInstance.getCallbackId(),
processInstance.getCallbackType(), processInstance.getId(), oldState, newState));
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Confirm the exact tenantId used at deployment time and pass that same value to the start call.
- Deploy the definition for the tenant if missing: createDeployment().tenantId(tenantId).addClasspathResource(...).deploy().
- List where the key exists: repositoryService.createProcessDefinitionQuery().processDefinitionKey(key).list() and read each definition's tenantId.
- Enable fallbackToDefaultTenant if falling back to the default tenant is acceptable in your setup.
Example fix
// before
runtimeService.startProcessInstanceByKey("order", "ACME", vars); // deployed as "acme"
// after
runtimeService.startProcessInstanceByKey("order", "acme", vars); // match deployment tenantId exactly Defensive patterns
Strategy: validation
Validate before calling
ProcessDefinition def = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey(key).processDefinitionTenantId(tenantId).latestVersion().singleResult();
if (def == null) {
throw new IllegalStateException("No definition key='" + key + "' tenantId='" + tenantId + "' — deploy it first");
} Try / catch
try {
return runtimeService.startProcessInstanceByKey(key, tenantId, vars);
} catch (FlowableObjectNotFoundException e) {
if (e.getMessage().contains("tenantId '" + tenantId + "' was not found")) {
repositoryService.createDeployment().addClasspathResource("processes/" + key + ".bpmn20.xml").tenantId(tenantId).deploy();
return runtimeService.startProcessInstanceByKey(key, tenantId, vars);
}
throw e;
} Prevention
- Read tenantId from the same source used at deployment time
- Match tenant id casing exactly (ids are case-sensitive)
- Script tenant deployments so every environment has all tenants
- Log the resolved tenantId when starting instances for easier diagnosis
When it happens
Trigger: startProcessInstanceByKey(key, tenantId, ...) variants (or resolveProcessDefinition called with fallbackToDefaultTenant=false) when the tenant never had this process deployed, including cases where the definition exists only under another tenant or the empty tenant.
Common situations: Wrong tenant id passed by configuration/env-var; process deployed with no tenant while the caller passes one; tenant ids case-mismatched; starting from an event/message path where the tenant was taken from a different source (e.g. user context) than the deployment.
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}
- No process definition found for key '${processDefinitionKey}
- No decision found for key <decisionKey>. There was also no f
- No decision found for key <decisionKey>. There was also no f
- Could not find deployment with id <deploymentId>
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/bf4558409361df27.
Report an issue: GitHub.