flowable/flowable-engine · error · FlowableIllegalArgumentException
jobId is null
Error message
jobId is null
What it means
DeleteHistoryJobCmd.getJobToDelete validates that historyJobId is non-null before querying the HistoryJobEntityManager. A null id results in FlowableIllegalArgumentException("jobId is null"). The command refuses to run a database lookup with an empty identifier.
Source
Thrown at modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/cmd/DeleteHistoryJobCmd.java:68
HistoryJobEntity jobToDelete = getJobToDelete(commandContext);
sendCancelEvent(jobToDelete);
jobServiceConfiguration.getHistoryJobEntityManager().delete(jobToDelete);
return null;
}
protected void sendCancelEvent(HistoryJobEntity jobToDelete) {
FlowableEventDispatcher eventDispatcher = jobServiceConfiguration.getEventDispatcher();
if (eventDispatcher != null && eventDispatcher.isEnabled()) {
eventDispatcher.dispatchEvent(FlowableJobEventBuilder.createEntityEvent(FlowableEngineEventType.JOB_CANCELED, jobToDelete),
jobServiceConfiguration.getEngineName());
}
}
protected HistoryJobEntity getJobToDelete(CommandContext commandContext) {
if (historyJobId == null) {
throw new FlowableIllegalArgumentException("jobId is null");
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Deleting job {}", historyJobId);
}
HistoryJobEntity job = jobServiceConfiguration.getHistoryJobEntityManager().findById(historyJobId);
if (job == null) {
throw new FlowableObjectNotFoundException("No history job found with id '" + historyJobId + "'", Job.class);
}
return job;
}
}
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Only build and execute DeleteHistoryJobCmd with an id obtained from a successful history job query result.
- Add a null/blank guard in the calling code to fail with a contextual message naming the source of the id.
- If history jobs may not exist, query historyJobEntityManager (or the history job query API) first and skip the delete when empty.
- Review recent refactors of the delete call for swapped/lost constructor arguments.
Example fix
// before
HistoryJobEntity job = ...; // may be null
managementService.executeCommand(new DeleteHistoryJobCmd(job != null ? job.getId() : null));
// after
HistoryJobEntity job = ...;
if (job != null) {
managementService.executeCommand(new DeleteHistoryJobCmd(job.getId()));
} Defensive patterns
Strategy: validation
Validate before calling
if (historyJobId == null || historyJobId.isBlank()) {
throw new IllegalArgumentException("historyJobId is required");
} Type guard
boolean hasHistoryJobId(String id) { return id != null && !id.isBlank(); } Try / catch
try {
managementService.executeCommand(new DeleteHistoryJobCmd(historyJobId));
} catch (FlowableIllegalArgumentException e) {
LOGGER.error("History job id missing: {}", e.getMessage());
} Prevention
- Only derive ids from non-null query results.
- Guard optional id sources (variables, maps) before command construction.
- Check async history is enabled if you expect history jobs to exist.
When it happens
Trigger: Executing DeleteHistoryJobCmd constructed with a null history job id, typically from API helpers where the id variable was never populated (e.g. a history job query returned no results and the code deleted a null id anyway).
Common situations: Async history cleanup scripts that iterate optional query results without checking for null; configuration where async history is disabled so no history jobs exist but code still attempts deletion; copy-pasted delete code using the wrong variable.
Related errors
- historyJobId is null
- historyJobId is null
- Error retrieving app engine info
- No deployment id available
- No resource name available
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/2c13c7e1214e4a97.
Report an issue: GitHub.