flowable/flowable-engine · error · FlowableIllegalArgumentException

The job id is mandatory, but

Error message

The job id is mandatory, but '${jobId}' has been provided.

What it means

Flowable throws this FlowableIllegalArgumentException in the SetTimerJobRetriesCmd constructor when the timer job id argument is null or an empty/blank string. The job id is the primary key used to locate the timer job entity, so without it the command can never succeed. It is fail-fast validation in the command constructor before any database access.

Solutions

  1. Ensure a non-empty timer job id is resolved before constructing the command
  2. Null/blank-check the id at the API boundary and surface a clear validation message to the caller
  3. Verify the id comes from the correct entity (a timer job id, not a process/execution id)
  4. Log the value being passed to catch empty-string propagation

Example fix

// before
String jobId = variables.get("jobId");
managementService.setTimerJobRetries(jobId, 3);
// after
String jobId = variables.get("jobId");
if (jobId == null || jobId.trim().isEmpty()) {
    throw new IllegalArgumentException("timerJobId must be provided");
}
managementService.setTimerJobRetries(jobId, 3);
Defensive patterns

Strategy: validation

Validate before calling

if (jobId == null || jobId.trim().isEmpty()) {
    throw new IllegalArgumentException("A non-empty timer job id is required");
}
managementService.setTimerJobRetries(jobId, retries);

Type guard

boolean isValidJobId(String id) { return id != null && !id.trim().isEmpty(); }

Prevention

When it happens

Trigger: Calling new SetTimerJobRetriesCmd(null, retries, config) or SetTimerJobRetriesCmd("", retries, config), or indirectly invoking ManagementService/setTimerJobRetries-style APIs where the jobId variable passed in was never initialized or came back empty from an upstream lookup.

Common situations: Passing a variable that was assigned from a map/getter that returned null; copying code from SetJobRetriesCmd and forgetting to supply the timer job id; deserializing a job id from config or a request payload where the field is optional and empty.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/cmd/SetTimerJobRetriesCmd.java:42

import org.flowable.job.api.Job;
import org.flowable.job.service.JobServiceConfiguration;
import org.flowable.job.service.event.impl.FlowableJobEventBuilder;
import org.flowable.job.service.impl.persistence.entity.TimerJobEntity;

/**
 * @author Tijs Rademakers
 */
public class SetTimerJobRetriesCmd implements Command<Void>, Serializable {

    private static final long serialVersionUID = 1L;

    protected final String jobId;
    protected final int retries;
    protected JobServiceConfiguration jobServiceConfiguration;

    public SetTimerJobRetriesCmd(String jobId, int retries, JobServiceConfiguration jobServiceConfiguration) {
        if (jobId == null || jobId.length() < 1) {
            throw new FlowableIllegalArgumentException("The job id is mandatory, but '" + jobId + "' has been provided.");
        }
        if (retries < 0) {
            throw new FlowableIllegalArgumentException("The number of job retries must be a non-negative Integer, but '" + retries + "' has been provided.");
        }
        this.jobId = jobId;
        this.retries = retries;
        this.jobServiceConfiguration = jobServiceConfiguration;
    }

    @Override
    public Void execute(CommandContext commandContext) {
        TimerJobEntity job = jobServiceConfiguration.getTimerJobEntityManager().findById(jobId);
        if (job != null) {

            job.setRetries(retries);

            FlowableEventDispatcher eventDispatcher = jobServiceConfiguration.getEventDispatcher();
            if (eventDispatcher != null && eventDispatcher.isEnabled()) {

View on GitHub (pinned to d6d39ce1c6)