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

  1. Deploy the process to the requested tenantId: createDeployment().tenantId(tenant).deploy().
  2. Verify the key spelling against ProcessDefinitionQuery.processDefinitionTenantId(tenant).processDefinitionKey(key).
  3. Check which tenants hold the key: repositoryService.createProcessDefinitionQuery().processDefinitionKey(key).list() and use the matching tenant.
  4. 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

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


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/1c7d690f8cdde3db. Report an issue: GitHub.