flowable/flowable-engine · error · FlowableException
Multiple timer jobs found for plan item instance
Error message
Multiple timer jobs found for plan item instance
What it means
RescheduleTimerJobCmd requires exactly one timer job for the event listener instance so it can deterministically reschedule it. When the query returns more than one job it throws FlowableException 'Multiple timer jobs found for plan item instance' because rescheduling an ambiguous set is unsafe.
Solutions
- Delete duplicate timer jobs so only one remains, then retry the reschedule
- Reschedule by explicit jobId (the other code path) instead of by eventListenerInstanceId
- Audit job creation code for accidental double insertion
- Report/upgrade if duplicates stem from a known engine bug
Example fix
// before
rescheduleTimer(eventListenerInstanceId, newDate); // throws if multiple jobs
// after
List<Job> jobs = jobService.createTimerJobQuery().planItemInstanceId(eventListenerInstanceId).list();
for (int i = 1; i < jobs.size(); i++) {
jobService.deleteJob(jobs.get(i).getId()); // dedupe extras
}
rescheduleTimer(eventListenerInstanceId, newDate); Defensive patterns
Strategy: validation
Validate before calling
long n = jobService.createTimerJobQuery().planItemInstanceId(eventListenerInstanceId).count();
if (n != 1) throw new IllegalStateException("Expected exactly 1 timer job, found " + n); Try / catch
try { reschedule(...); } catch (FlowableException e) { log.error("Ambiguous timer jobs for {}: {}", eventListenerInstanceId, e.getMessage()); } Prevention
- Reschedule by explicit jobId when uniqueness cannot be guaranteed
- Deduplicate timer jobs before rescheduling
- Monitor for duplicate job creation as an engine/config regression
When it happens
Trigger: Multiple timer jobs existing for a single plan item instance id — caused by reschedule/duplicate logic bugs, repeated job creation during retries, or manually inserting jobs.
Common situations: Engines upgraded mid-flight leaving duplicated timer jobs; custom code creating additional timers for the same listener; async executor retry corner cases.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- No plan item instance found for id
- No timer jobs found for plan item instance
- Timer job not found for id
- A dynamically created plan item can only be injected into a…
- A dynamically created plan item can only be injected into a…
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/59d78c04783e5fa9.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/RescheduleTimerJobCmd.java:68
@Override
public Job execute(CommandContext commandContext) {
String timerJobId = null;
PlanItemInstance planItemInstance = null;
JobService jobService = CommandContextUtil.getJobService(commandContext);
if (eventListenerInstanceId != null) {
planItemInstance = CommandContextUtil.getPlanItemInstanceEntityManager(commandContext).findById(eventListenerInstanceId);
if (planItemInstance == null) {
throw new FlowableObjectNotFoundException("No plan item instance found for id " + eventListenerInstanceId);
}
List<Job> timerJobs = jobService.createTimerJobQuery().planItemInstanceId(eventListenerInstanceId).list();
if (timerJobs == null || timerJobs.isEmpty()) {
throw new FlowableException("No timer jobs found for plan item instance " + eventListenerInstanceId);
}
if (timerJobs.size() > 1) {
throw new FlowableException("Multiple timer jobs found for plan item instance " + eventListenerInstanceId);
}
timerJobId = timerJobs.get(0).getId();
} else {
timerJobId = jobId;
}
TimerJobService timerJobService = CommandContextUtil.getTimerJobService(commandContext);
TimerJobEntity timerJob = timerJobService.findTimerJobById(timerJobId);
if (timerJob == null) {
throw new FlowableObjectNotFoundException("Timer job not found for id " + timerJobId);
}
if (planItemInstance == null) {
planItemInstance = CommandContextUtil.getPlanItemInstanceEntityManager(commandContext).findById(timerJob.getSubScopeId());
if (planItemInstance == null) {
throw new FlowableException("Plan item instance not found for id " + timerJob.getSubScopeId());View on GitHub (pinned to d6d39ce1c6)