{"record":{"id":"3d4a9d2780f71ad5","repo":"flowable/flowable-engine","slug":"empty-external-worker-job-can-not-be-scheduled","errorCode":null,"errorMessage":"Empty external worker job can not be scheduled","messagePattern":"Empty external worker job 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":167,"sourceCode":"        // 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\n    public JobEntity moveExternalWorkerJobToExecutableJob(ExternalWorkerJobEntity externalWorkerJob) {\n        if (externalWorkerJob == null) {\n            throw new FlowableException(\"Empty external worker job can not be scheduled\");\n        }\n\n        JobEntity executableJob = createExecutableJobFromOtherJob(externalWorkerJob);\n        // This job should now become a regular async job\n        fillDefaultAsyncJobInfo(executableJob, executableJob.isExclusive());\n        boolean insertSuccessful = jobServiceConfiguration.getJobEntityManager().insertJobEntity(executableJob);\n        if (insertSuccessful) {\n            jobServiceConfiguration.getExternalWorkerJobEntityManager().delete(externalWorkerJob);\n            triggerExecutorIfNeeded(executableJob);\n            return executableJob;\n        }\n        return null;\n    }\n\n    @Override\n    public TimerJobEntity moveJobToTimerJob(AbstractRuntimeJobEntity job) {\n        TimerJobEntity timerJob = createTimerJobFromOtherJob(job);\n        boolean insertSuccessful = jobServiceConfiguration.getTimerJobEntityManager().insertTimerJobEntity(timerJob);","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/asyncexecutor/DefaultJobManager.java#L149-L185","documentation":"DefaultJobManager.moveExternalWorkerJobToExecutableJob converts an ExternalWorkerJobEntity (locked external-worker job) into a regular executable JobEntity. A null external worker job cannot be scheduled, so the method throws this FlowableException as a fail-fast precondition.","triggerScenarios":"Passing null to JobManager.moveExternalWorkerJobToExecutableJob(externalWorkerJob), usually when an external-worker job fetch or lock result was null and passed through unchecked.","commonSituations":"Custom external-worker acquisition/timeout handling code; races where the external worker job was already completed or deleted before the move.","solutions":["Null-check externalWorkerJob before calling the method and skip/log on null","Fix upstream acquisition code that yields null entities","Catch the FlowableException and re-fetch the job state to handle lifecycle races"],"exampleFix":"// before\njobManager.moveExternalWorkerJobToExecutableJob(externalWorkerJob);\n// after\nif (externalWorkerJob != null) {\n    jobManager.moveExternalWorkerJobToExecutableJob(externalWorkerJob);\n}","handlingStrategy":"validation","validationCode":"if (externalWorkerJob == null) { log.warn(\"No external worker job to move\"); return; }","typeGuard":"boolean canSchedule(ExternalWorkerJobEntity j) { return j != null && j.getId() != null; }","tryCatchPattern":"try { jobManager.moveExternalWorkerJobToExecutableJob(job); } catch (FlowableException e) { log.warn(\"External worker job absent before move: {}\", e.getMessage()); }","preventionTips":["Null-check external-worker job lookups before moving","Account for concurrent completion/deletion by workers","Guard custom external-worker acquisition code at boundaries"],"tags":["flowable","job-scheduling","null-check","external-worker"],"backgroundTag":"null-argument","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"}