{"record":{"id":"f25de5357cbd0ccf","repo":"flowable/flowable-engine","slug":"there-must-be-at-least-one-job-entity-manager","errorCode":null,"errorMessage":"there must be at least one job entity manager","messagePattern":"there must be at least one job entity manager","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/asyncexecutor/ResetExpiredJobsRunnable.java","lineNumber":56,"sourceCode":" */\npublic class ResetExpiredJobsRunnable implements Runnable {\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(ResetExpiredJobsRunnable.class);\n\n    protected final String name;\n    protected final AsyncExecutor asyncExecutor;\n    protected final Collection<JobInfoEntityManager<? extends JobInfoEntity>> jobInfoEntityManagers;\n\n    protected volatile boolean isInterrupted;\n    protected final Object MONITOR = new Object();\n    protected final AtomicBoolean isWaiting = new AtomicBoolean(false);\n\n    public ResetExpiredJobsRunnable(String name, AsyncExecutor asyncExecutor,\n            JobInfoEntityManager<? extends JobInfoEntity>... jobEntityManagers) {\n        this.name = name;\n        this.asyncExecutor = asyncExecutor;\n        if (jobEntityManagers.length < 1) {\n            throw new IllegalArgumentException(\"there must be at least one job entity manager\");\n        }\n        this.jobInfoEntityManagers = Arrays.asList(jobEntityManagers);\n    }\n\n    @Override\n    public synchronized void run() {\n        LOGGER.info(\"starting to reset expired jobs for engine {}\", getEngineName());\n        Thread.currentThread().setName(name);\n\n        while (!isInterrupted) {\n\n            resetJobs();\n\n            // Sleep\n            try {\n\n                synchronized (MONITOR) {\n                    if (!isInterrupted) {","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/asyncexecutor/ResetExpiredJobsRunnable.java#L38-L74","documentation":"ResetExpiredJobsRunnable is constructed with a varargs array of job entity managers it must scan to reset expired (locked-but-stale) jobs. The constructor enforces that at least one manager is supplied, throwing IllegalArgumentException otherwise. Without a manager the runnable would have nothing to reset, which is a programming error, not a runtime condition.","triggerScenarios":"new ResetExpiredJobsRunnable(name, asyncExecutor) with an empty varargs array — typically in custom async executor bootstrap code that builds the runnable manually.","commonSituations":"Custom AsyncExecutor implementations that construct ResetExpiredJobsRunnable directly without passing the timer/message job entity managers; test scaffolding forgetting the managers.","solutions":["Pass at least one JobInfoEntityManager (e.g. jobEntityManager, timerJobEntityManager) when constructing the runnable.","If using the standard DefaultAsyncJobExecutor, let it wire the runnable instead of constructing it manually.","Guard custom bootstrap code with a length check / config source so managers are always provided."],"exampleFix":"// before\nresetExpiredJobsRunnable = new ResetExpiredJobsRunnable(\"reset\", asyncExecutor);\n\n// after\nresetExpiredJobsRunnable = new ResetExpiredJobsRunnable(\"reset\", asyncExecutor,\n    jobServiceConfiguration.getJobEntityManager(),\n    jobServiceConfiguration.getTimerJobEntityManager());","handlingStrategy":"validation","validationCode":"if (jobEntityManagers == null || jobEntityManagers.length == 0) {\n    throw new IllegalArgumentException(\"ResetExpiredJobsRunnable requires at least one job entity manager\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pass job and timer job entity managers to the constructor.","Prefer letting DefaultAsyncJobExecutor wire the runnable.","Add a constructor-level assertion in custom executor bootstrap code."],"tags":["flowable","async-executor","constructor","varargs"],"backgroundTag":"invalid-constructor-argument","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}