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
DeadLetterJobQueryImpl.timers() throws FlowableIllegalArgumentException when onlyMessages is already set on the query. onlyTimers(), onlyMessages(), and onlyExternalWorkers() are mutually exclusive job-type filters; combining them would produce contradictory criteria, so the second call fails fast. The message text mentions onlyMessages because that flag was set first.
Source
Thrown at modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/DeadLetterJobQueryImpl.java:429
this.handlerTypes = handlerTypes;
}
return this;
}
@Override
public DeadLetterJobQueryImpl executable() {
if (inOrStatement) {
this.currentOrQueryObject.executable = true;
} else {
this.executable = true;
}
return this;
}
@Override
public DeadLetterJobQueryImpl timers() {
if (onlyMessages) {
throw new FlowableIllegalArgumentException("Cannot combine onlyTimers() with onlyMessages() in the same query");
}
if (onlyExternalWorkers) {
throw new FlowableIllegalArgumentException("Cannot combine onlyExternalWorkers() with onlyMessages() in the same query");
}
if (inOrStatement) {
this.currentOrQueryObject.onlyTimers = true;
} else {
this.onlyTimers = true;
}
return this;
}
@Override
public DeadLetterJobQueryImpl messages() {
if (onlyTimers) {
throw new FlowableIllegalArgumentException("Cannot combine onlyTimers() with onlyMessages() in the same query");
}View on GitHub (pinned to d6d39ce1c6)
Solutions
- Pick exactly one job-type filter per query: only onlyTimers(), onlyMessages(), or onlyExternalWorkers().
- If multiple types are needed, run separate queries and merge the results in application code.
- Always start from a fresh managementService.createDeadLetterJobQuery() instead of reusing a configured query object.
Example fix
// before
DeadLetterJobQuery q = mgmt.createDeadLetterJobQuery().onlyMessages();
if (includeTimers) { q.timers(); } // throws
// after
DeadLetterJobQuery q = mgmt.createDeadLetterJobQuery();
if (includeTimers) {
q = mgmt.createDeadLetterJobQuery().timers();
} else {
q = mgmt.createDeadLetterJobQuery().onlyMessages();
} Defensive patterns
Strategy: validation
Validate before calling
int typeFilters = (useTimers ? 1 : 0) + (useMessages ? 1 : 0) + (useExternalWorkers ? 1 : 0);
if (typeFilters > 1) { throw new IllegalArgumentException("Select at most one of timers/messages/externalWorkers"); } Type guard
boolean canApplyTypeFilter(DeadLetterJobQueryImpl q) { return !q.onlyMessages && !q.onlyExternalWorkers; } Try / catch
try { query.timers(); } catch (FlowableIllegalArgumentException e) { log.warn("Conflicting job type filters: {}", e.getMessage()); query = managementService.createDeadLetterJobQuery(); } Prevention
- Never reuse a query instance across different filter configurations
- Translate multi-select UI options into separate queries merged in code
- Centralize dead-letter query construction in one helper that enforces a single type filter
When it happens
Trigger: Calling deadLetterJobQuery().onlyMessages()...timers() (or vice versa) on the same query object; also triggers when onlyExternalWorkers was set and timers() is called (with its own companion message). Reusing a cached/shared query instance that already carries one of these flags.
Common situations: Building query filters dynamically from user-selected checkboxes that allow multiple type selections; appending filters to a shared query template; merging two queries' criteria into one object.
Related errors
- Cannot combine onlyTimers() with onlyMessages() in the same
- appsDefinitionIds is null
- Empty appsDefinitionIds
- category is null
- query is null
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/e2cbb545bb7e3a66.
Report an issue: GitHub.