flowable/flowable-engine · error · FlowableIllegalArgumentException

The number of job retries must be a non-negative Integer…

Error message

The number of job retries must be a non-negative Integer, but '${retries}' has been provided.

What it means

The SetJobRetriesCmd constructor also validates the retries parameter and throws FlowableIllegalArgumentException when retries is negative. Retry counts must be >= 0 because they configure how many more times a failed job may be attempted; a negative value is nonsensical.

Solutions

  1. Clamp the retry count to Math.max(0, retries) before calling setJobRetries.
  2. Validate configuration values for retries are non-negative at startup.
  3. Fix the arithmetic that can produce a negative count.

Example fix

// before
managementService.setJobRetries(jobId, currentRetries - decrements);
// after
int newRetries = Math.max(0, currentRetries - decrements);
managementService.setJobRetries(jobId, newRetries);
Defensive patterns

Strategy: validation

Validate before calling

if (retries < 0) throw new IllegalArgumentException("retries must be >= 0");

Type guard

boolean validRetries = retries >= 0;

Try / catch

try { managementService.setJobRetries(jobId, retries); } catch (FlowableIllegalArgumentException e) { log.error("Invalid retries value: {}", e.getMessage()); }

Prevention

When it happens

Trigger: Calling ManagementService.setJobRetries(jobId, retries) with retries < 0, e.g. computing retries via subtraction that underflows or a config value parsed incorrectly.

Common situations: Decrementing current retries without flooring at zero; property files/env vars with negative or misparsed values; arithmetic on retry counts in retry-management tooling.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

/**
 * @author Falko Menge
 */
public class SetJobRetriesCmd implements Command<Void>, Serializable {

    private static final long serialVersionUID = 1L;
    
    protected JobServiceConfiguration jobServiceConfiguration;

    protected final String jobId;
    protected final int retries;

    public SetJobRetriesCmd(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) {
        JobEntity job = jobServiceConfiguration.getJobEntityManager().findById(jobId);
        if (job != null) {

            job.setRetries(retries);

            FlowableEventDispatcher eventDispatcher = jobServiceConfiguration.getEventDispatcher();
            if (eventDispatcher != null && eventDispatcher.isEnabled()) {
                eventDispatcher.dispatchEvent(FlowableJobEventBuilder.createEntityEvent(FlowableEngineEventType.ENTITY_UPDATED, job),
                        jobServiceConfiguration.getEngineName());
            }

View on GitHub (pinned to d6d39ce1c6)