flowable/flowable-engine · error · FlowableIllegalArgumentException

Cannot combine onlyTimers() with onlyMessages() in the same

Error message

Cannot combine onlyTimers() with onlyMessages() in the same query

What it means

FlowableIllegalArgumentException thrown by JobQueryImpl.timers() when onlyMessages is already set on the query. The onlyTimers and onlyMessages filters are mutually exclusive: a job is either a timer job or a message/async job, so combining both would yield a logically empty query. Flowable rejects the combination at query-build time.

Source

Thrown at modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/JobQueryImpl.java:412

    }

    @Override
    public JobQuery handlerTypes(Collection<String> handlerTypes) {
        if (handlerTypes == null) {
            throw new FlowableIllegalArgumentException("Provided handlerTypes are null");
        }
        if (inOrStatement) {
            this.currentOrQueryObject.handlerTypes = handlerTypes;
        } else {
            this.handlerTypes = handlerTypes;
        }
        return this;
    }

    @Override
    public JobQuery timers() {
        if (onlyMessages) {
            throw new FlowableIllegalArgumentException("Cannot combine onlyTimers() with onlyMessages() in the same query");
        }
        if (inOrStatement) {
            this.currentOrQueryObject.onlyTimers = true;
        } else {
            this.onlyTimers = true;
        }
        return this;
    }

    @Override
    public JobQuery messages() {
        if (onlyTimers) {
            throw new FlowableIllegalArgumentException("Cannot combine onlyTimers() with onlyMessages() in the same query");
        }
        if (inOrStatement) {
            this.currentOrQueryObject.onlyMessages = true;
        } else {
            this.onlyMessages = true;

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Call only one of timers() or messages() per query; drop the conflicting call.
  2. Track which filter was set and use onlyMessages()/onlyTimers() mutually exclusively in your builder.
  3. If both job kinds are needed, run two separate queries and merge results instead of one query with both flags.
  4. To remove a previously set filter, build a fresh JobQueryImpl rather than flipping flags.

Example fix

// before
if (filterTimers) query.timers();
if (filterMessages) query.messages(); // throws when both true

// after
if (filterTimers && filterMessages) {
    // run two queries, or treat as 'no filter'
} else if (filterTimers) {
    query.timers();
} else if (filterMessages) {
    query.messages();
}
Defensive patterns

Strategy: validation

Validate before calling

if (filterTimers && filterMessages) {
    throw new IllegalArgumentException("timers and messages filters are mutually exclusive; run separate queries");
}

Try / catch

try {
    query.timers();
} catch (org.flowable.common.engine.api.FlowableIllegalArgumentException e) {
    // onlyMessages already set: rebuild the query with only one kind filter
    query = jobService.createJobQuery();
}

Prevention

When it happens

Trigger: Calling jobQuery.timers() after jobQuery.messages() on the same query instance, or building a query with conditionally-added filters where both flags end up set (also applies inside an or() block).

Common situations: Dynamic query builders that add filters based on user-selected checkboxes where 'timers' and 'messages' were both selected; copy-pasted query code accumulating both flags.

Related errors


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