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

  1. Delete duplicate timer jobs so only one remains, then retry the reschedule
  2. Reschedule by explicit jobId (the other code path) instead of by eventListenerInstanceId
  3. Audit job creation code for accidental double insertion
  4. 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

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


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)