flowable/flowable-engine · error · FlowableIllegalArgumentException

version must be positive

Error message

version must be positive

What it means

DecisionQueryImpl.checkVersion(Integer) throws FlowableIllegalArgumentException("version must be positive") when a version filter method receives an Integer <= 0. DMN decision versions start at 1, so 0 or negative numbers can never match and are treated as invalid input, rejected before the query executes.

Source

Thrown at modules/flowable-dmn-engine/src/main/java/org/flowable/dmn/engine/impl/DecisionQueryImpl.java:232

    @Override
    public DmnDecisionQuery decisionVersionLowerThan(Integer decisionVersion) {
        checkVersion(decisionVersion);
        this.versionLt = decisionVersion;
        return this;
    }

    @Override
    public DmnDecisionQuery decisionVersionLowerThanOrEquals(Integer decisionVersion) {
        checkVersion(decisionVersion);
        this.versionLte = decisionVersion;
        return this;
    }

    protected void checkVersion(Integer version) {
        if (version == null) {
            throw new FlowableIllegalArgumentException("version is null");
        } else if (version <= 0) {
            throw new FlowableIllegalArgumentException("version must be positive");
        }
    }

    @Override
    public DecisionQueryImpl latestVersion() {
        this.latest = true;
        return this;
    }

    @Override
    public DmnDecisionQuery decisionTenantId(String tenantId) {
        if (tenantId == null) {
            throw new FlowableIllegalArgumentException("decision tenantId is null");
        }
        this.tenantId = tenantId;
        return this;
    }

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Pass a version >= 1; add an input check like `if (version < 1) throw ...` before calling the query.
  2. If version is unknown/unset, avoid the version filter entirely or use latestVersion().
  3. Check the numbering convention of the upstream source and add +1 offsets if it starts at 0.

Example fix

// before
int version = 0; // default
query.decisionVersion(version);
// after
if (version >= 1) {
    query.decisionVersion(version);
} else {
    query.latestVersion();
}
Defensive patterns

Strategy: validation

Validate before calling

if (version != null && version >= 1) {
    query.decisionVersion(version);
} else {
    query.latestVersion();
}

Type guard

boolean isValidVersion(Integer v) { return v != null && v > 0; }

Try / catch

try {
    query.decisionVersion(version);
} catch (FlowableIllegalArgumentException e) {
    if (e.getMessage() != null && e.getMessage().contains("positive")) {
        query.latestVersion();
    } else { throw e; }
}

Prevention

When it happens

Trigger: Calling decisionVersion(0), decisionVersion(-1), decisionVersionGreaterThan(0), etc. — typically versions initialized to 0 as a sentinel, off-by-one arithmetic, or unvalidated user input.

Common situations: Defaults like `int version = 0;` that are never overwritten when config/lookup fails; loop arithmetic or subtraction yielding 0/negative; external systems that report versions starting at 0 while Flowable starts at 1.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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