flowable/flowable-engine · error · FlowableIllegalArgumentException
jobId is null
Error message
jobId is null
What it means
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.
Source
Thrown at modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/cmd/DeleteTimerJobCmd.java:68
TimerJobEntity jobToDelete = getJobToDelete(commandContext);
sendCancelEvent(commandContext, jobToDelete);
jobServiceConfiguration.getTimerJobEntityManager().delete(jobToDelete);
return null;
}
protected void sendCancelEvent(CommandContext commandContext, TimerJobEntity jobToDelete) {
FlowableEventDispatcher eventDispatcher = jobServiceConfiguration.getEventDispatcher();
if (eventDispatcher != null && eventDispatcher.isEnabled()) {
eventDispatcher.dispatchEvent(FlowableJobEventBuilder.createEntityEvent(FlowableEngineEventType.JOB_CANCELED, jobToDelete),
jobServiceConfiguration.getEngineName());
}
}
protected TimerJobEntity getJobToDelete(CommandContext commandContext) {
if (timerJobId == null) {
throw new FlowableIllegalArgumentException("jobId is null");
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Deleting job {}", timerJobId);
}
TimerJobEntity job = jobServiceConfiguration.getTimerJobEntityManager().findById(timerJobId);
if (job == null) {
throw new FlowableObjectNotFoundException("No timer job found with id '" + timerJobId + "'", Job.class);
}
// We need to check if the job was locked, ie acquired by the job acquisition thread
// This happens if the job was already acquired, but not yet executed.
// In that case, we can't allow to delete the job.
if (job.getLockOwner() != null) {
throw new FlowableException("Cannot delete " + job + " when the job is being executed. Try again later.");
}
return job;
}View on GitHub (pinned to d6d39ce1c6)
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.
Example fix
// before
managementService.deleteTimerJob(timerJobId); // NPEs inside command
// after
if (timerJobId == null) {
throw new IllegalArgumentException("timerJobId must be provided");
}
managementService.deleteTimerJob(timerJobId); Defensive patterns
Strategy: validation
Validate before calling
if (timerJobId == null) { throw new IllegalArgumentException("timerJobId must not be null before deleteTimerJob"); } Try / catch
try { managementService.deleteTimerJob(timerJobId); } catch (FlowableIllegalArgumentException e) { /* null id — fix caller */ } Prevention
- 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.
When it happens
Trigger: Calling managementService.deleteTimerJob(null) or constructing new DeleteTimerJobCmd(null) directly and executing it via the command executor.
Common situations: 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.
Related errors
- The timer job id is mandatory, but 'null' has been provided.
- Provided execution id is null
- Empty timer job can not be scheduled
- No timer job found with id '
- jobId is null
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/30cb49ab27c1c3e3.
Report an issue: GitHub.