{"record":{"id":"23da2d73c9e2b11c","repo":"Activiti/Activiti","slug":"cannot-combine-onlytimers-with-onlymessages-in-23da2d","errorCode":null,"errorMessage":"Cannot combine onlyTimers() with onlyMessages() in the same query","messagePattern":"Cannot combine onlyTimers\\(\\) with onlyMessages\\(\\) in the same query","errorType":"validation","errorClass":"ActivitiIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"activiti-core/activiti-engine/src/main/java/org/activiti/engine/impl/JobQueryImpl.java","lineNumber":111,"sourceCode":"            throw new ActivitiIllegalArgumentException(\"Provided execution id is null\");\n        }\n        this.executionId = executionId;\n        return this;\n    }\n\n    public JobQuery withRetriesLeft() {\n        retriesLeft = true;\n        return this;\n    }\n\n    public JobQuery executable() {\n        executable = true;\n        return this;\n    }\n\n    public JobQuery timers() {\n        if (onlyMessages) {\n            throw new ActivitiIllegalArgumentException(\n                \"Cannot combine onlyTimers() with onlyMessages() in the same query\"\n            );\n        }\n        this.onlyTimers = true;\n        return this;\n    }\n\n    public JobQuery messages() {\n        if (onlyTimers) {\n            throw new ActivitiIllegalArgumentException(\n                \"Cannot combine onlyTimers() with onlyMessages() in the same query\"\n            );\n        }\n        this.onlyMessages = true;\n        return this;\n    }\n\n    public JobQuery duedateHigherThan(Date date) {","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/Activiti/Activiti/blob/56435b1a97deeafdc09dd40074b056c89fba5a8a/activiti-core/activiti-engine/src/main/java/org/activiti/engine/impl/JobQueryImpl.java#L93-L129","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Choose exactly one of timers() or messages() per query based on the desired job type","If you want all jobs, call neither method (the default matches both timer and message jobs)","Restructure dynamic filter code into if/else so only one branch executes","Build a fresh JobQuery instance for each query instead of mutating a shared one"],"exampleFix":"// before\nJobQuery query = managementService.createJobQuery();\nif (config.showMessages) query.messages();\nif (config.showTimers) query.timers();\n// after\nJobQuery query = managementService.createJobQuery();\nif (config.showMessages && !config.showTimers) {\n    query.messages();\n} else if (config.showTimers && !config.showMessages) {\n    query.timers();\n}","handlingStrategy":"validation","validationCode":"// Java\nif (onlyTimers && onlyMessages) {\n    throw new IllegalArgumentException(\"Choose either timer or message jobs for a single query; omit both for all jobs\");\n}","typeGuard":"// Java\nJobQuery applyJobType(JobQuery q, boolean timers, boolean messages) {\n    if (timers && !messages) return q.timers();\n    if (messages && !timers) return q.messages();\n    return q; // default: both\n}","tryCatchPattern":"// Java\ntry {\n    jobs = buildJobQuery(criteria).list();\n} catch (ActivitiIllegalArgumentException e) {\n    if (e.getMessage().contains(\"onlyTimers() with onlyMessages()\")) {\n        throw new BadRequestException(\"Cannot filter by both timer and message jobs in one query\");\n    }\n    throw e;\n}","preventionTips":["Model the job type as a single enum (ALL/TIMER/MESSAGE) rather than two booleans","Never mutate a shared/reused JobQuery instance across requests","Remember neither timers() nor messages() returns all job types","If both types are needed, run two queries and merge the results"],"tags":["activiti","invalid-argument","query-validation","java"],"backgroundTag":"mutually-exclusive-options","analyzedSha":"56435b1a97deeafdc09dd40074b056c89fba5a8a","analyzedAt":"2026-09-09T21:00:06.703Z","contentChangedAt":"2026-09-09T21:00:06.703Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}