flowable/flowable-engine · error · FlowableIllegalArgumentException

Cannot combine onlyTimers() with onlyExternalWorkers() in…

Error message

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

What it means

SuspendedJobQueryImpl.externalWorkers() restricts the query to jobs handled by external workers. The library throws this FlowableIllegalArgumentException because onlyTimers() and onlyExternalWorkers() are mutually exclusive filters: a job cannot simultaneously be a timer job and an external-worker job. Allowing the combination would produce a query that can never match any row.

Solutions

  1. Remove either onlyTimers() or externalWorkers() from the query chain so only one job-type filter remains.
  2. If both timer and external-worker jobs are needed, run two separate queries and merge the results in application code.
  3. Check for filters set inside or() blocks; the flag may have been set on the currentOrQueryObject in an earlier builder call.
  4. If the intent was to exclude timers rather than select them, remove onlyTimers() and use externalWorkers() alone.

Example fix

// before
SuspendedJobQuery q = jobService.createSuspendedJobQuery().onlyTimers().externalWorkers();
// after
SuspendedJobQuery q = jobService.createSuspendedJobQuery().externalWorkers();
Defensive patterns

Strategy: validation

Validate before calling

// before building
boolean wantsTimers = /* ... */;
boolean wantsExternalWorkers = /* ... */;
if (wantsTimers && wantsExternalWorkers) {
    throw new IllegalArgumentException("Pick either onlyTimers() or externalWorkers(), not both");
}

Try / catch

try {
    query = jobService.createSuspendedJobQuery().externalWorkers().list();
} catch (FlowableIllegalArgumentException e) {
    // fall back to a single-filter query
    query = jobService.createSuspendedJobQuery().externalWorkers().list();
}

Prevention

When it happens

Trigger: Calling suspendedJobQuery() then .onlyTimers().externalWorkers() (or the reverse order) on a SuspendedJobQueryImpl, including inside an or() block where currentOrQueryObject.externalWorkers() is invoked after onlyTimers() was set on that same or-object.

Common situations: Developers building a 'show me everything pending' query add both timer and external-worker filters thinking they are additive, or copy-paste a query builder chain that already filtered by timers. Also occurs when refactoring from onlyMessages() to externalWorkers() without removing the timer filter.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/SuspendedJobQueryImpl.java:481

            throw new FlowableIllegalArgumentException("Cannot combine onlyExternalWorkers() with onlyMessages() in the same query");
        }

        if (inOrStatement) {
            this.currentOrQueryObject.onlyMessages = true;
        } else {
            this.onlyMessages = true;
        }
        return this;
    }

    @Override
    public SuspendedJobQueryImpl externalWorkers() {
        if (onlyMessages) {
            throw new FlowableIllegalArgumentException("Cannot combine onlyMessages() with onlyExternalWorkers() in the same query");
        }

        if (onlyTimers) {
            throw new FlowableIllegalArgumentException("Cannot combine onlyTimers() with onlyExternalWorkers() in the same query");
        }

        if (inOrStatement) {
            this.currentOrQueryObject.onlyExternalWorkers = true;
        } else {
            this.onlyExternalWorkers = true;
        }
        return this;
    }

    @Override
    public SuspendedJobQueryImpl duedateHigherThan(Date date) {
        if (date == null) {
            throw new FlowableIllegalArgumentException("Provided date is null");
        }
        if (inOrStatement) {
            this.currentOrQueryObject.duedateHigherThan = date;
        } else {

View on GitHub (pinned to d6d39ce1c6)