Activiti/Activiti · error · ActivitiIllegalArgumentException

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

Error message

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

What it means

JobQuery.timers() selects only timer jobs, and it is mutually exclusive with messages(), which selects only message jobs. If onlyMessages was already set on this query, calling timers() would produce a contradictory filter, so the engine throws ActivitiIllegalArgumentException. This is a query-construction misuse detected at build time.

Solutions

  1. Choose exactly one of timers() or messages() per query based on the desired job type
  2. If you want all jobs, call neither method (the default matches both timer and message jobs)
  3. Restructure dynamic filter code into if/else so only one branch executes
  4. Build a fresh JobQuery instance for each query instead of mutating a shared one

Example fix

// before
JobQuery query = managementService.createJobQuery();
if (config.showMessages) query.messages();
if (config.showTimers) query.timers();
// after
JobQuery query = managementService.createJobQuery();
if (config.showMessages && !config.showTimers) {
    query.messages();
} else if (config.showTimers && !config.showMessages) {
    query.timers();
}
Defensive patterns

Strategy: validation

Validate before calling

// Java
if (onlyTimers && onlyMessages) {
    throw new IllegalArgumentException("Choose either timer or message jobs for a single query; omit both for all jobs");
}

Type guard

// Java
JobQuery applyJobType(JobQuery q, boolean timers, boolean messages) {
    if (timers && !messages) return q.timers();
    if (messages && !timers) return q.messages();
    return q; // default: both
}

Try / catch

// Java
try {
    jobs = buildJobQuery(criteria).list();
} catch (ActivitiIllegalArgumentException e) {
    if (e.getMessage().contains("onlyTimers() with onlyMessages()")) {
        throw new BadRequestException("Cannot filter by both timer and message jobs in one query");
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling .messages().timers() (or calling timers() twice on the same JobQuery object after messages() was set), e.g. when the job type is chosen dynamically from a config value and both branches end up applied to a shared query instance.

Common situations: Reusable query-builder code that conditionally adds both filters, a config flag like jobType set to an unexpected value that triggers both branches, or copying settings from another query object onto the same instance.

Related errors


AI-assisted analysis of Activiti/Activiti@56435b1a97 (2026-09-09). Data as JSON: /api/errors/23da2d73c9e2b11c. Report an issue: GitHub.

Appendix: source

Thrown at activiti-core/activiti-engine/src/main/java/org/activiti/engine/impl/JobQueryImpl.java:111

            throw new ActivitiIllegalArgumentException("Provided execution id is null");
        }
        this.executionId = executionId;
        return this;
    }

    public JobQuery withRetriesLeft() {
        retriesLeft = true;
        return this;
    }

    public JobQuery executable() {
        executable = true;
        return this;
    }

    public JobQuery timers() {
        if (onlyMessages) {
            throw new ActivitiIllegalArgumentException(
                "Cannot combine onlyTimers() with onlyMessages() in the same query"
            );
        }
        this.onlyTimers = true;
        return this;
    }

    public JobQuery messages() {
        if (onlyTimers) {
            throw new ActivitiIllegalArgumentException(
                "Cannot combine onlyTimers() with onlyMessages() in the same query"
            );
        }
        this.onlyMessages = true;
        return this;
    }

    public JobQuery duedateHigherThan(Date date) {

View on GitHub (pinned to 56435b1a97)