{"record":{"id":"f8c016f0e4e5719f","repo":"flowable/flowable-engine","slug":"only-one-of-timersonly-or-messagesonly-can-be-f8c016","errorCode":null,"errorMessage":"Only one of 'timersOnly' or 'messagesOnly' can be provided.","messagePattern":"Only one of 'timersOnly' or 'messagesOnly' can be provided\\.","errorType":"http","errorClass":"FlowableIllegalArgumentException","httpStatus":400,"severity":"error","filePath":"modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/management/TimerJobCollectionResource.java","lineNumber":127,"sourceCode":"        if (allRequestParams.containsKey(\"caseDefinitionId\")) {\n            query.caseDefinitionId(allRequestParams.get(\"caseDefinitionId\"));\n        }\n        if (allRequestParams.containsKey(\"scopeDefinitionId\")) {\n            query.scopeDefinitionId(allRequestParams.get(\"scopeDefinitionId\"));\n            query.scopeType(ScopeTypes.CMMN);\n        }\n        if (allRequestParams.containsKey(\"elementId\")) {\n            query.elementId(allRequestParams.get(\"elementId\"));\n        }\n        if (allRequestParams.containsKey(\"elementName\")) {\n            query.elementName(allRequestParams.get(\"elementName\"));\n        }\n        if (allRequestParams.containsKey(\"executable\")) {\n            query.executable();\n        }\n        if (allRequestParams.containsKey(\"timersOnly\")) {\n            if (allRequestParams.containsKey(\"messagesOnly\")) {\n                throw new FlowableIllegalArgumentException(\"Only one of 'timersOnly' or 'messagesOnly' can be provided.\");\n            }\n            if (Boolean.parseBoolean(allRequestParams.get(\"timersOnly\"))) {\n                query.timers();\n            }\n        }\n        if (allRequestParams.containsKey(\"messagesOnly\") && Boolean.parseBoolean(allRequestParams.get(\"messagesOnly\"))) {\n            query.messages();\n        }\n        if (allRequestParams.containsKey(\"dueBefore\")) {\n            query.duedateLowerThan(RequestUtil.getDate(allRequestParams, \"dueBefore\"));\n        }\n        if (allRequestParams.containsKey(\"dueAfter\")) {\n            query.duedateHigherThan(RequestUtil.getDate(allRequestParams, \"dueAfter\"));\n        }\n        if (allRequestParams.containsKey(\"withException\") && Boolean.parseBoolean(allRequestParams.get(\"withException\"))) {\n            query.withException();\n        }\n        if (allRequestParams.containsKey(\"exceptionMessage\")) {","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/management/TimerJobCollectionResource.java#L109-L145","documentation":"The CMMN job query REST endpoint (TimerJobCollectionResource.getJobs) accepts optional 'timersOnly' and 'messagesOnly' query parameters to filter timer vs message jobs. Because the two filters are mutually exclusive (one maps to query.timers(), the other to query.messages()), passing both is ambiguous and the endpoint rejects the request with FlowableIllegalArgumentException before executing the query.","triggerScenarios":"GET /cmmn-query/jobs?timersOnly=true&messagesOnly=true — both parameters present as request params, regardless of their boolean values (presence alone triggers the check).","commonSituations":"A client builds query strings dynamically from a filter object and accidentally includes both flags; a generic job-listing UI exposes both toggles and sends both when both are checked; copy-pasted URLs accumulate stale params.","solutions":["Send only one of 'timersOnly' or 'messagesOnly' in the query string.","If the client needs both timer and message jobs, omit both parameters to get all jobs and filter client-side.","In the client, enforce exclusivity: if both flags are true, clear one before building the request."],"exampleFix":"// before\nconst params = new URLSearchParams();\nif (filters.timersOnly) params.set('timersOnly', 'true');\nif (filters.messagesOnly) params.set('messagesOnly', 'true');\n// after\nconst params = new URLSearchParams();\nif (filters.timersOnly && !filters.messagesOnly) params.set('timersOnly', 'true');\nelse if (filters.messagesOnly) params.set('messagesOnly', 'true');","handlingStrategy":"validation","validationCode":"function canQueryJobs(filters) {\n  const both = filters.timersOnly !== undefined && filters.messagesOnly !== undefined;\n  return !both;\n}\nif (!canQueryJobs(filters)) throw new Error('Send only timersOnly or messagesOnly');","typeGuard":null,"tryCatchPattern":"try {\n  const jobs = await getJobs(params);\n} catch (e) {\n  if (e.response?.status === 400 && /timersOnly/.test(e.response.data?.message)) {\n    params = pickSingleFilter(params); // resend with one flag\n  }\n}","preventionTips":["Model the filter as an enum (timer|message|all) instead of two booleans.","Build query strings from a whitelist of allowed params.","Unit-test the URL builder for mutually exclusive params."],"tags":["rest-api","query-parameters","validation"],"backgroundTag":"mutually-exclusive-options","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}