{"record":{"id":"f06f0a2233e79a9e","repo":"flowable/flowable-engine","slug":"callbackids-is-null-or-empty","errorCode":null,"errorMessage":"callbackIds is null or empty","messagePattern":"callbackIds is null or empty","errorType":"exception","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/HistoricCaseInstanceQueryImpl.java","lineNumber":744,"sourceCode":"    }\n\n    @Override\n    public HistoricCaseInstanceQuery caseInstanceCallbackId(String callbackId) {\n        if (callbackId == null) {\n            throw new FlowableIllegalArgumentException(\"callback id is null\");\n        }\n        if (inOrStatement) {\n            this.currentOrQueryObject.callbackId = callbackId;\n        } else {\n            this.callbackId = callbackId;\n        }\n        return this;\n    }\n\n    @Override\n    public HistoricCaseInstanceQuery caseInstanceCallbackIds(Set<String> callbackIds) {\n        if (callbackIds == null || callbackIds.isEmpty()) {\n            throw new FlowableIllegalArgumentException(\"callbackIds is null or empty\");\n        }\n        if (inOrStatement) {\n            this.currentOrQueryObject.callbackIds = callbackIds;\n        } else {\n            this.callbackIds = callbackIds;\n        }\n        return this;\n    }\n    \n    @Override\n    public HistoricCaseInstanceQuery caseInstanceCallbackType(String callbackType) {\n        if (callbackType == null) {\n            throw new FlowableIllegalArgumentException(\"callback type is null\");\n        }\n        if (inOrStatement) {\n            this.currentOrQueryObject.callbackType = callbackType;\n        } else {\n            this.callbackType = callbackType;","sourceCodeStart":726,"sourceCodeEnd":762,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/HistoricCaseInstanceQueryImpl.java#L726-L762","documentation":"HistoricCaseInstanceQueryImpl.caseInstanceCallbackIds(Set<String>) validates that the callbackIds set is non-null and non-empty before storing it as a query filter. Flowable query implementations reject empty criteria because they would either produce an invalid SQL IN clause or silently match nothing. Throwing FlowableIllegalArgumentException fails fast at query-building time instead of at execution time.","triggerScenarios":"Calling caseInstanceCallbackIds(null) or caseInstanceCallbackIds(new HashSet<>()) (any empty Set) on a HistoricCaseInstanceQuery, directly or inside an or() block.","commonSituations":"Collecting callback ids from an upstream list that turned out empty and passing the collection straight into the query; a variable initialized to an empty set and never populated; refactoring that replaced a single callbackId call with the plural set-based API.","solutions":["Pass a Set containing at least one non-null callback id string.","Skip adding the callback-ids filter (or use a different query branch) when the set is empty instead of calling the method.","If a null/empty set is a valid 'no filter' case in your code, check isEmpty() before building the query and choose the appropriate query variant."],"exampleFix":"// before\nquery.caseInstanceCallbackIds(callbackIds);\n// after\nif (callbackIds != null && !callbackIds.isEmpty()) {\n    query.caseInstanceCallbackIds(callbackIds);\n}","handlingStrategy":"validation","validationCode":"// Java\nif (callbackIds == null || callbackIds.isEmpty()) {\n    throw new IllegalStateException(\"callbackIds must contain at least one id\");\n}\nquery.caseInstanceCallbackIds(callbackIds);","typeGuard":"boolean hasCallbackIds(Set<String> s) { return s != null && !s.isEmpty(); }","tryCatchPattern":"try {\n    query.caseInstanceCallbackIds(callbackIds);\n} catch (FlowableIllegalArgumentException e) {\n    // fall back to query without callback-id filter\n    log.warn(\"Ignoring callbackIds filter: {}\", e.getMessage());\n}","preventionTips":["Never pass collections straight from upstream sources into Flowable query filters without an isEmpty() check.","Centralize query building in a helper that validates all filter inputs.","When migrating from single-id to set-based filter methods, check the set is populated."],"tags":["null-argument","query","cmmn","validation"],"backgroundTag":"empty-required-field","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}