{"record":{"id":"30cb49ab27c1c3e3","repo":"flowable/flowable-engine","slug":"jobid-is-null-30cb49","errorCode":null,"errorMessage":"jobId is null","messagePattern":"jobId is null","errorType":"validation","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/cmd/DeleteTimerJobCmd.java","lineNumber":68,"sourceCode":"        TimerJobEntity jobToDelete = getJobToDelete(commandContext);\n\n        sendCancelEvent(commandContext, jobToDelete);\n\n        jobServiceConfiguration.getTimerJobEntityManager().delete(jobToDelete);\n        return null;\n    }\n\n    protected void sendCancelEvent(CommandContext commandContext, TimerJobEntity jobToDelete) {\n        FlowableEventDispatcher eventDispatcher = jobServiceConfiguration.getEventDispatcher();\n        if (eventDispatcher != null && eventDispatcher.isEnabled()) {\n            eventDispatcher.dispatchEvent(FlowableJobEventBuilder.createEntityEvent(FlowableEngineEventType.JOB_CANCELED, jobToDelete),\n                    jobServiceConfiguration.getEngineName());\n        }\n    }\n\n    protected TimerJobEntity getJobToDelete(CommandContext commandContext) {\n        if (timerJobId == null) {\n            throw new FlowableIllegalArgumentException(\"jobId is null\");\n        }\n        if (LOGGER.isDebugEnabled()) {\n            LOGGER.debug(\"Deleting job {}\", timerJobId);\n        }\n\n        TimerJobEntity job = jobServiceConfiguration.getTimerJobEntityManager().findById(timerJobId);\n        if (job == null) {\n            throw new FlowableObjectNotFoundException(\"No timer job found with id '\" + timerJobId + \"'\", Job.class);\n        }\n\n        // We need to check if the job was locked, ie acquired by the job acquisition thread\n        // This happens if the job was already acquired, but not yet executed.\n        // In that case, we can't allow to delete the job.\n        if (job.getLockOwner() != null) {\n            throw new FlowableException(\"Cannot delete \" + job + \" when the job is being executed. Try again later.\");\n        }\n        return job;\n    }","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/cmd/DeleteTimerJobCmd.java#L50-L86","documentation":"DeleteTimerJobCmd validates its timerJobId constructor argument before doing anything else, throwing FlowableIllegalArgumentException when it is null. The library requires an explicit timer job id because deletion is keyed entirely on it. This is a caller-side programming error, not a data or engine state problem.","triggerScenarios":"Calling managementService.deleteTimerJob(null) or constructing new DeleteTimerJobCmd(null) directly and executing it via the command executor.","commonSituations":"Java delegating code builds the command from a variable that was never assigned; callers of custom job-service code pass an id fetched from an API response that came back null; refactors changed a method signature and an id parameter is silently no longer populated.","solutions":["Check that the timer job id passed to ManagementService.deleteTimerJob is non-null before calling it.","If the id comes from a prior query (e.g. timer job list), verify the query actually returned a job and you took its id.","Log the id source at the call site to find where the null originates.","Add a unit test asserting non-null id for your delete wrapper method."],"exampleFix":"// before\nmanagementService.deleteTimerJob(timerJobId); // NPEs inside command\n// after\nif (timerJobId == null) {\n    throw new IllegalArgumentException(\"timerJobId must be provided\");\n}\nmanagementService.deleteTimerJob(timerJobId);","handlingStrategy":"validation","validationCode":"if (timerJobId == null) { throw new IllegalArgumentException(\"timerJobId must not be null before deleteTimerJob\"); }","typeGuard":null,"tryCatchPattern":"try { managementService.deleteTimerJob(timerJobId); } catch (FlowableIllegalArgumentException e) { /* null id — fix caller */ }","preventionTips":["Never pass raw nullable id variables into delete* APIs; resolve them via a TimerJobQuery first.","Keep ids in Optional<String> in wrapper code and require a value before invoking.","Log the id source at call sites to trace null origins quickly."],"tags":["flowable","job-service","null-argument","timer-job"],"backgroundTag":"null-argument","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}