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

  1. Validate jobId != null before calling moveJobToDeadLetterJob.
  2. Guard batch move loops to skip null ids with a log entry.
  3. 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

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)