flowable/flowable-engine · error · FlowableIllegalArgumentException
jobId and job is null
Error message
jobId and job is null
What it means
MoveJobToDeadLetterJobCmd.execute() requires a jobId and throws FlowableIllegalArgumentException with message 'jobId and job is null' when it is null. The command looks up the job in the timer-job then job tables and moves it to the dead-letter table; a null id makes that impossible.
Solutions
- Validate jobId != null before calling moveJobToDeadLetterJob.
- Guard batch move loops to skip null ids with a log entry.
- Fix the upstream producer of the null id (query result, message payload).
Example fix
// before managementService.moveJobToDeadLetterJob(jobId); // after Objects.requireNonNull(jobId, "jobId required"); managementService.moveJobToDeadLetterJob(jobId);
Defensive patterns
Strategy: validation
Validate before calling
if (jobId == null || jobId.isEmpty()) throw new IllegalArgumentException("jobId required to move to dead-letter"); Type guard
boolean hasId = jobId != null && !jobId.isEmpty();
Try / catch
try { managementService.moveJobToDeadLetterJob(jobId); } catch (FlowableIllegalArgumentException e) { log.error("Move failed: {}", e.getMessage()); } Prevention
- Validate ids at the edge of your admin tooling
- Skip-and-log null ids in loops
- Use Optional<String> for job ids to force explicit handling
When it happens
Trigger: Calling ManagementService.moveJobToDeadLetterJob(jobId) with a null jobId, or executing the command directly without an id.
Common situations: Job id read from a nullable event/variable; admin tooling sending an empty form field; retry scripts that pass null when the previous step failed.
Related errors
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/782179daddb9f7c3.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/cmd/MoveJobToDeadLetterJobCmd.java:48
public class MoveJobToDeadLetterJobCmd implements Command<DeadLetterJobEntity>, Serializable {
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = LoggerFactory.getLogger(MoveJobToDeadLetterJobCmd.class);
protected String jobId;
protected JobServiceConfiguration jobServiceConfiguration;
public MoveJobToDeadLetterJobCmd(String jobId, JobServiceConfiguration jobServiceConfiguration) {
this.jobId = jobId;
this.jobServiceConfiguration = jobServiceConfiguration;
}
@Override
public DeadLetterJobEntity execute(CommandContext commandContext) {
if (jobId == null) {
throw new FlowableIllegalArgumentException("jobId and job is null");
}
AbstractRuntimeJobEntity job = jobServiceConfiguration.getTimerJobEntityManager().findById(jobId);
if (job == null) {
job = jobServiceConfiguration.getJobEntityManager().findById(jobId);
}
if (job == null) {
throw new JobNotFoundException(jobId);
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Moving job to deadletter job table {}", job.getId());
}
DeadLetterJobEntity deadLetterJob = jobServiceConfiguration.getJobManager().moveJobToDeadLetterJob(job);
return deadLetterJob;View on GitHub (pinned to d6d39ce1c6)