flowable/flowable-engine · error · FlowableException

No timer jobs found for plan item instance

Error message

No timer jobs found for plan item instance 

What it means

RescheduleTimerJobCmd expects exactly one timer job for the given event listener plan item instance. When the timer job query returns no jobs it throws FlowableException 'No timer jobs found for plan item instance' because there is nothing to reschedule.

Solutions

  1. Query the job first: jobService/createTimerJobQuery().planItemInstanceId(id).count() and only reschedule when count == 1
  2. Check async executor state — a misconfigured async executor can leave no pending timer jobs
  3. Confirm tenant/category filters match the job's
  4. Catch FlowableException and treat already-fired timers as a benign case

Example fix

// before
rescheduleTimer(eventListenerInstanceId, newDate);
// after
if (jobService.createTimerJobQuery().planItemInstanceId(eventListenerInstanceId).count() == 1) {
    rescheduleTimer(eventListenerInstanceId, newDate);
} else {
    logger.warn("No (or multiple) timer jobs for {}, skipping reschedule", eventListenerInstanceId);
}
Defensive patterns

Strategy: validation

Validate before calling

long n = jobService.createTimerJobQuery().planItemInstanceId(eventListenerInstanceId).count();
if (n == 0) throw new IllegalStateException("No timer job to reschedule for " + eventListenerInstanceId);

Try / catch

try { reschedule(...); } catch (FlowableException e) { log.warn("Timer already fired or absent for {}", eventListenerInstanceId); }

Prevention

When it happens

Trigger: Rescheduling an event listener instance that has no active timer job — e.g. the timer already fired, was cancelled, the listener never started a timer, or the job service query filters (tenant, category) exclude it.

Common situations: Calling reschedule twice (first call moves the job out of the timer job table); timer already expired and moved to the dead-letter/history tables; wrong tenant scoping hiding the job.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/RescheduleTimerJobCmd.java:64

        this.newDueDate = newDueDate;
        this.newDateValue = newDateValue;
    }

    @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);
        }
        

View on GitHub (pinned to d6d39ce1c6)