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

  1. Only build and execute DeleteHistoryJobCmd with an id obtained from a successful history job query result.
  2. Add a null/blank guard in the calling code to fail with a contextual message naming the source of the id.
  3. If history jobs may not exist, query historyJobEntityManager (or the history job query API) first and skip the delete when empty.
  4. 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

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


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/2c13c7e1214e4a97. Report an issue: GitHub.