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
- Verify a deployed (non-deleted) definition exists: repositoryService.createProcessDefinitionQuery().processDefinitionKey(key).latestVersion().singleResult(); redeploy the BPMN if missing
- Check tenant alignment: compare job.getTenantId() (ACT_RU_JOB.TENANT_ID_) with the definition's tenant; redeploy with matching tenant or null-tenant
- Delete the orphan timer-start job via managementService.deleteJob if the process is intentionally gone
- 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
- Deploy the BPMN under the same tenantId used by existing timer jobs
- Never delete a deployment holding timer-start jobs without cascade or recreating the schedule afterwards
- Keep <process id="..."> stable across redeploys; the job references this key
- After undeploying, query and clean leftover timer-start jobs in ACT_RU_JOB
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
- no processes deployed with key '" + processDefinitionKey + "
- No process definition found for key '<processDefinitionKey>'
- Error while firing timer: border event activity ${nestedActi
- exception during timer execution: ${message}
- no processes deployed with key '<processDefinitionKey>' for
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/87b578c25be69567.
Report an issue: GitHub.