flowable/flowable-engine · error · FlowableIllegalArgumentException
jobId is null
Error message
jobId is null
What it means
ExecuteAsyncJobCmd throws FlowableIllegalArgumentException when its jobId constructor argument is null. Asynchronous job execution is keyed purely on the id, so a null id makes the command meaningless and is rejected up front.
Source
Thrown at modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/cmd/ExecuteAsyncJobCmd.java:64
}
public ExecuteAsyncJobCmd(String jobId, JobInfoEntityManager<? extends JobInfoEntity> jobEntityManager,
JobServiceConfiguration jobServiceConfiguration) {
this.jobId = jobId;
this.jobEntityManager = jobEntityManager;
this.jobServiceConfiguration = jobServiceConfiguration;
}
@Override
public Object execute(CommandContext commandContext) {
if (jobEntityManager == null) {
jobEntityManager = jobServiceConfiguration.getJobEntityManager(); // Backwards compatibility
}
if (jobId == null) {
throw new FlowableIllegalArgumentException("jobId is null");
}
// We need to refetch the job, as it could have been deleted by another concurrent job
// For example: an embedded subprocess with a couple of async tasks and a timer on the boundary of the subprocess
// when the timer fires, all executions and thus also the jobs inside of the embedded subprocess are destroyed.
// However, the async task jobs could already have been fetched and put in the queue.... while in reality they have been deleted.
// A refetch is thus needed here to be sure that it exists for this transaction.
JobInfoEntity job = jobEntityManager.findById(jobId);
if (job == null) {
LOGGER.debug("Job does not exist anymore and will not be executed. It has most likely been deleted "
+ "as part of another concurrent part of the process instance.");
return null;
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Executing async job {}", job.getId());
}View on GitHub (pinned to d6d39ce1c6)
Solutions
- Ensure the id passed to the command/executor API is non-null before dispatching.
- If the id comes from a queued message, guard the deserialization step so null ids are dropped with a log line.
- Check custom executor wrappers that may pass a variable initialized to null.
- Add an assert/early return in the code that builds the command.
Example fix
// before commandExecutor.execute(new ExecuteAsyncJobCmd(jobId)); // jobId may be null // after Objects.requireNonNull(jobId, "jobId must not be null"); commandExecutor.execute(new ExecuteAsyncJobCmd(jobId));
Defensive patterns
Strategy: validation
Validate before calling
if (jobId == null || jobId.isBlank()) { throw new IllegalArgumentException("jobId required for ExecuteAsyncJobCmd"); } Try / catch
try { commandExecutor.execute(new ExecuteAsyncJobCmd(jobId)); } catch (FlowableIllegalArgumentException e) { LOGGER.error("Rejected async job execution: {}", e.getMessage()); } Prevention
- Validate ids at your service boundary before building commands.
- Drop queued messages with null ids early and log them.
- Use Objects.requireNonNull in wrappers around executor calls.
When it happens
Trigger: Executing new ExecuteAsyncJobCmd(null) via the command executor, or async executor continuation paths passing a null job id after a fetch/dequeue produced nothing.
Common situations: Custom job executor code enqueuing jobs where the id field was never set; wrapper APIs forwarding an optional id that the caller omitted; tests invoking the command directly without arguments.
Related errors
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/38f252ce9a94d899.
Report an issue: GitHub.