{"record":{"id":"a1a38996e0d5306a","repo":"flowable/flowable-engine","slug":"empty-timer-jobs-collection-can-not-be-scheduled","errorCode":null,"errorMessage":"Empty timer jobs collection can not be scheduled","messagePattern":"Empty timer jobs collection can not be scheduled","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/asyncexecutor/DefaultJobManager.java","lineNumber":146,"sourceCode":"        if (timerJob == null) {\n            throw new FlowableException(\"Empty timer job can not be scheduled\");\n        }\n\n        JobEntity executableJob = createExecutableJobFromOtherJob(timerJob);\n        boolean insertSuccessful = jobServiceConfiguration.getJobEntityManager().insertJobEntity(executableJob);\n        if (insertSuccessful) {\n            jobServiceConfiguration.getTimerJobEntityManager().delete(timerJob);\n            triggerExecutorIfNeeded(executableJob);\n            return executableJob;\n        }\n        return null;\n    }\n\n    @Override\n    public void bulkMoveTimerJobsToExecutableJobs(List<TimerJobEntity> timerJobEntities) {\n\n        if (timerJobEntities == null || timerJobEntities.isEmpty()) {\n            throw new FlowableException(\"Empty timer jobs collection can not be scheduled\");\n        }\n\n        // Only hint when there is enough capacity remaining in the job queue\n        boolean remainingCapacitySufficient = isAsyncExecutorRemainingCapacitySufficient(timerJobEntities.size());\n\n        for (TimerJobEntity timerJobEntity : timerJobEntities) {\n            JobEntity executableJob = createExecutableJobFromOtherJob(timerJobEntity, remainingCapacitySufficient);\n\n            boolean insertSuccessful = jobServiceConfiguration.getJobEntityManager().insertJobEntity(executableJob);\n            if (insertSuccessful && remainingCapacitySufficient) {\n                triggerExecutorIfNeeded(executableJob);\n            }\n        }\n\n        jobServiceConfiguration.getTimerJobEntityManager().bulkDeleteTimerJobsWithoutRevisionCheck(timerJobEntities);\n    }\n\n    @Override","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/asyncexecutor/DefaultJobManager.java#L128-L164","documentation":"DefaultJobManager.bulkMoveTimerJobsToExecutableJobs moves a batch of timer jobs to the executable job table in one operation. A null or empty list means there is nothing to move, and the method throws this FlowableException as a precondition rather than performing a no-op.","triggerScenarios":"Calling bulkMoveTimerJobsToExecutableJobs(null) or with an empty List, e.g. forwarding the result of a timer-job query that matched nothing.","commonSituations":"Batch schedulers that query due timer jobs and always call the bulk move even when zero rows were due; tests or utilities exercising the API with empty inputs.","solutions":["Skip the call when the collection is null or empty: if (jobs == null || jobs.isEmpty()) return;","Guard in the acquisition layer so empty batches never reach the bulk move","If you control the query, add due-date criteria so only non-empty batches are produced"],"exampleFix":"// before\njobManager.bulkMoveTimerJobsToExecutableJobs(dueTimerJobs);\n// after\nif (dueTimerJobs != null && !dueTimerJobs.isEmpty()) {\n    jobManager.bulkMoveTimerJobsToExecutableJobs(dueTimerJobs);\n}","handlingStrategy":"validation","validationCode":"if (timerJobEntities == null || timerJobEntities.isEmpty()) { return; }","typeGuard":"boolean isNonEmptyBatch(List<TimerJobEntity> l) { return l != null && !l.isEmpty(); }","tryCatchPattern":"try { jobManager.bulkMoveTimerJobsToExecutableJobs(jobs); } catch (FlowableException e) { log.warn(\"Empty batch passed to bulk move: {}\", e.getMessage()); }","preventionTips":["Skip empty batches before calling bulk APIs","Check acquisition query results for empty results","Centralize batch-move logic in one guarded helper"],"tags":["flowable","job-scheduling","empty-collection"],"backgroundTag":"empty-required-field","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}