flowable/flowable-engine · error · ActivitiException

Could not find process definition needed for timer start eve

Error message

Could not find process definition needed for timer start event

What it means

TimerStartEventJobHandler throws this when a timer-start job fires but no deployed process definition can be resolved for its processDefinitionKey — neither latest overall nor latest for the job's tenant. The deployment manager returned null from findDeployedLatestProcessDefinitionByKey(ByTenantId).

Source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/jobexecutor/TimerStartEventJobHandler.java:89

            LOGGER.debug("Ignoring timer of suspended process definition {}", processDefinition.getId());
        }

    }

    protected void startProcessDefinitionByKey(Job job, String configuration, DeploymentManager deploymentManager, CommandContext commandContext) {

        // it says getActivityId, but < 5.21, this would have the process definition key stored
        String processDefinitionKey = TimerEventHandler.getActivityIdFromConfiguration(configuration);

        ProcessDefinition processDefinition = null;
        if (job.getTenantId() == null || ProcessEngineConfiguration.NO_TENANT_ID.equals(job.getTenantId())) {
            processDefinition = deploymentManager.findDeployedLatestProcessDefinitionByKey(processDefinitionKey);
        } else {
            processDefinition = deploymentManager.findDeployedLatestProcessDefinitionByKeyAndTenantId(processDefinitionKey, job.getTenantId());
        }

        if (processDefinition == null) {
            throw new ActivitiException("Could not find process definition needed for timer start event");
        }

        try {
            if (!deploymentManager.isProcessDefinitionSuspended(processDefinition.getId())) {
                dispatchTimerFiredEvent(job, commandContext);

                new StartProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, null, null, job.getTenantId()).execute(commandContext);
            } else {
                LOGGER.debug("Ignoring timer of suspended process definition {}", processDefinition.getId());
            }
        } catch (RuntimeException e) {
            LOGGER.error("exception during timer execution", e);
            throw e;
        } catch (Exception e) {
            LOGGER.error("exception during timer execution", e);
            throw new ActivitiException("exception during timer execution: " + e.getMessage(), e);
        }
    }

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Verify a deployed (non-deleted) definition exists: repositoryService.createProcessDefinitionQuery().processDefinitionKey(key).latestVersion().singleResult(); redeploy the BPMN if missing
  2. Check tenant alignment: compare job.getTenantId() (ACT_RU_JOB.TENANT_ID_) with the definition's tenant; redeploy with matching tenant or null-tenant
  3. Delete the orphan timer-start job via managementService.deleteJob if the process is intentionally gone
  4. For time-based start events, confirm the job's PROCESS_DEFINITION_KEY_ matches the bpmn <process id="...">

Example fix

// before: deployed with tenant but job created without one (or vice versa)
repositoryService.createDeployment().addClasspathResource("process.bpmn").tenantId("acme").deploy();
// after: keep tenant consistent with existing timer jobs
repositoryService.createDeployment().addClasspathResource("process.bpmn")
    .tenantId(jobTenantIdIfAny) // or omit tenantId to match null-tenant jobs
    .deploy();
Defensive patterns

Strategy: validation

Validate before calling

ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
    .processDefinitionKey(key)
    .processDefinitionTenantId(tenantId) // match the job's tenant, or omit for null-tenant
    .latestVersion().singleResult();
if (pd == null) throw new IllegalStateException("timer start key " + key + " not deployed for tenant " + tenantId);

Type guard

boolean isDeployed(String key, String tenantId) {
  ProcessDefinitionQuery q = repositoryService.createProcessDefinitionQuery()
      .processDefinitionKey(key).latestVersion();
  return (tenantId != null ? q.processDefinitionTenantId(tenantId) : q)
      .singleResult() != null;
}

Try / catch

try {
  managementService.executeJob(startTimerJobId);
} catch (FlowableException e) {
  if (e.getMessage() != null && e.getMessage().contains("Could not find process definition needed for timer start event")) {
    log.error("timer start job orphaned for key={}, tenant={}", key, tenantId);
    managementService.deleteJob(startTimerJobId);
  } else { throw e; }
}

Prevention

When it happens

Trigger: A timer start event job exists in ACT_RU_JOB for a process definition key whose latest deployed definition was deleted (repositoryService.deleteDeployment without cascade of the key), or the definition was deployed under a different tenantId than the job's tenant.

Common situations: Multi-tenant setups where the timer job carries a tenantId but the definition was deployed with no tenant (or vice versa); undeploying/replacing a process while its timer-start job survives; typo in process key between redeploys.

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/87b578c25be69567. Report an issue: GitHub.